diff --git a/docs/pages/guides/recipes/multitenancy/custom-data-model-per-tenant.mdx b/docs/pages/guides/recipes/multitenancy/custom-data-model-per-tenant.mdx
index 6c0745196eddf..e9120696c2737 100644
--- a/docs/pages/guides/recipes/multitenancy/custom-data-model-per-tenant.mdx
+++ b/docs/pages/guides/recipes/multitenancy/custom-data-model-per-tenant.mdx
@@ -67,10 +67,10 @@ module.exports = {
## Data modeling
-### Customizing publicity
+### Customizing member-level access
-The simplest way to customize the data models is by changing the [publicity][ref-publicity]
-of data model entities. It works great for use cases when tenants share parts of
+The simplest way to customize the data models is by changing the [member-level access][ref-mls]
+to data model entities. It works great for use cases when tenants share parts of
their data models.
By setting the `public` parameter of [cubes][ref-cubes-public], [views][ref-views-public],
@@ -168,7 +168,7 @@ cube(`cube_x`, {
-For your convenience, [Playground][ref-playground] ignores publicity configration
+For your convenience, [Playground][ref-playground] ignores member-level access configration
and marks data model entities that are not accessible for querying through
[APIs][ref-apis] with the lock icon.
@@ -182,8 +182,8 @@ And here's the *perspective* of `Bob`:
### Customizing other parameters
-Similarly to [customizing publicity](#customizing-publicity), you can set other
-parameters of data model entities for each tenant individually:
+Similarly to [customizing member-level access](#customizing-member-level-access),
+you can set other parameters of data model entities for each tenant individually:
- By setting `sql` or [`sql_table` parameters][ref-cube-sql-table] of cubes, you
can ensure that each tenant accesses data from its own tables or database schemas.
@@ -364,7 +364,7 @@ code that fetches data model files for each tenant.
[ref-scheduled-refresh-contexts]: /reference/configuration/config#scheduled_refresh_contexts
[ref-context-to-app-id]: /reference/configuration/config#context_to_app_id
[ref-config-files]: /product/configuration#cubepy-and-cubejs-files
-[ref-publicity]: /product/data-modeling/concepts/publicity
+[ref-mls]: /product/auth/member-level-security
[ref-cubes-public]: /reference/data-model/cube#public
[ref-views-public]: /reference/data-model/view#public
[ref-measures-public]: /reference/data-model/measures#public
diff --git a/docs/pages/guides/style-guide.mdx b/docs/pages/guides/style-guide.mdx
index 1e4bc38e62ea1..8224e1cc0177f 100644
--- a/docs/pages/guides/style-guide.mdx
+++ b/docs/pages/guides/style-guide.mdx
@@ -70,12 +70,14 @@ cube_project
- `description`
- `public`
- `refresh_key`
+ - `meta`
- `pre_aggregations`
- `joins`
- `dimensions`
- `hierarchies`
- `segments`
- `measures`
+ - `access_policy`
### Dimensions & measures
@@ -141,6 +143,7 @@ cubes:
- `public`
- `cubes`
- `folders`
+ - `access_policy`
### Example view
diff --git a/docs/pages/product/_meta.js b/docs/pages/product/_meta.js
index d1326632afc38..fd3fb9b793fbd 100644
--- a/docs/pages/product/_meta.js
+++ b/docs/pages/product/_meta.js
@@ -4,7 +4,7 @@ module.exports = {
"configuration": "Configuration",
"data-modeling": "Data modeling",
"caching": "Caching",
- "auth": "Authentication & authorization",
+ "auth": "Access control",
"apis-integrations": "APIs & integrations",
"workspace": "Workspace",
"deployment": "Deployment",
diff --git a/docs/pages/product/apis-integrations.mdx b/docs/pages/product/apis-integrations.mdx
index ebd26c51a323e..82c7b3fe48c8c 100644
--- a/docs/pages/product/apis-integrations.mdx
+++ b/docs/pages/product/apis-integrations.mdx
@@ -48,7 +48,7 @@ for an unofficial, community-maintained [client library for Python](https://gith
-### Support for data modeling
+### Data modeling
Support for data modeling features differ across APIs, integrations, and [visualization
tools][ref-viz-tools]. Some of the features with partial support are listed below:
@@ -58,6 +58,17 @@ tools][ref-viz-tools]. Some of the features with partial support are listed belo
| [Hierarchies][ref-hierarchies] | ✅ [Tableau][ref-tableau] via [Semantic Layer Sync][ref-sls]
✅ Cube Cloud for Excel
✅ [Cube Cloud for Sheets][ref-cube-cloud-for-sheets] | ❌ All other tools |
| [Folders][ref-folders] | ✅ [Tableau][ref-tableau] via [Semantic Layer Sync][ref-sls]
✅ Cube Cloud for Excel
✅ [Cube Cloud for Sheets][ref-cube-cloud-for-sheets] | ❌ All other tools |
+### Authentication methods
+
+Support for authentication methods differ across APIs, integrations, and [visualization
+tools][ref-viz-tools]:
+
+| Method | Supported in |
+| --- | --- |
+| [User name and password][ref-auth-user-pass] | ✅ [SQL API][ref-sql-api] and [Semantic Layer Sync][ref-sls]
✅ [MDX API][ref-mdx-api] |
+| [Identity provider][ref-auth-idp] | ✅ Cube Cloud for Excel
✅ [Cube Cloud for Sheets][ref-cube-cloud-for-sheets] |
+| [Access token][ref-auth-tokens] | ✅ [REST API][ref-rest-api]
✅ [GraphQL API][ref-graphql-api]
✅ [AI API][ref-ai-api] |
+
## Management APIs
In case you'd like Cube to work with data orchestration tools and let them push
@@ -83,4 +94,7 @@ API][ref-orchestration-api].
[ref-viz-tools]: /product/configuration/visualization-tools
[ref-hierarchies]: /reference/data-model/hierarchies
[ref-folders]: /reference/data-model/view#folders
-[ref-tableau]: /product/configuration/visualization-tools/tableau
\ No newline at end of file
+[ref-tableau]: /product/configuration/visualization-tools/tableau
+[ref-auth-user-pass]: /product/auth#user-name-and-password
+[ref-auth-idp]: /product/auth#identity-provider
+[ref-auth-tokens]: /product/auth#access-token
\ No newline at end of file
diff --git a/docs/pages/product/auth.mdx b/docs/pages/product/auth.mdx
index 3825a1bc4e626..be27c6d3313f4 100644
--- a/docs/pages/product/auth.mdx
+++ b/docs/pages/product/auth.mdx
@@ -1,11 +1,55 @@
----
-redirect_from:
- - /security
----
+# Access control
-# Overview
+Cube supports a few methods to authenticates requests to [APIs & integrations][ref-apis].
+Usually, an API supports authentication via [one of these methods][ref-apis-methods]:
+
+* [User name and password](#user-name-and-password) (e.g., used by the [SQL API][ref-sql-api]).
+* [Identity provider](#identity-provider) (e.g., used by the [Cube Cloud for Sheets][ref-cube-cloud-sheets]).
+* [Access token](#access-token) (e.g., used by the [REST API][ref-rest-api]).
+
+Regardless of the method, the authentication flow includes the following steps:
+
+* User identity information (e.g., password or access token) is passed to Cube.
+* Cube validates the identity information or trusts the identity provider.
+* User identity information is optionally enriched with additional attributes,
+such the user's role, via [authentication integration](#authentication-integration).
+* Finally, the API request is associated with a [security context][ref-sec-ctx].
+It is then used to configure [member-level security][ref-mls]
+and [row-level security][ref-rls] as well as set [data access policies][ref-dap].
+
+## User name and password
+
+Some visualization tools (e.g., BI tools) can pass user name and, sometimes, password to Cube.
+
+### Configuration
+
+Relevant configuration options: [`check_sql_auth`][ref-config-check-sql-auth] and [`can_switch_sql_user`][ref-config-can-switch-sql-user].
+
+Relevant environment variables: `CUBEJS_SQL_USER`, `CUBEJS_SQL_PASSWORD`, `CUBEJS_SQL_SUPER_USER`.
+
+## Identity provider
+
+Some visualization tools (e.g., [Cube Cloud for Sheets][ref-cube-cloud-sheets]) implement
+an OAuth 2.0 flow to authenticate users.
+
+
+
+OAuth 2.0 flow is available in Cube Cloud on [Premium and above](https://cube.dev/pricing) product tiers.
+
+
+
+During this flow, users are redirected to a login page of an identity provider (e.g., Google)
+where they enter their credentials. Then, the identity provider passes the user identity
+information to Cube Cloud.
+
+This method does not require any configuration.
+
+## Access token
+
+Some visualization tools (e.g., custom front-end applications) can pass access tokens based
+on the [JSON Web Token][wiki-jwt] (JWT) standard to Cube. These tokens can be either generated
+by these applications or obtained from an identity provider. Cube then validates these tokens.
-In Cube, authorization (or access control) is based on the **security context**.
The diagram below shows how it works during the request processing in Cube:
@@ -16,18 +60,44 @@ The diagram below shows how it works during the request processing in Cube:
/>
-Authentication is handled outside of Cube. A typical use case would be:
+### Configuration
+
+Relevant configuration options: [`check_auth`][ref-config-check-auth] and [`jwt`][ref-config-jwt].
+
+Relevant environment variables: `CUBEJS_API_SECRET`, `CUBEJS_JWT_KEY`, `CUBEJS_JWK_URL`,
+`CUBEJS_JWT_AUDIENCE`, `CUBEJS_JWT_ISSUER`, `CUBEJS_JWT_SUBJECT`, `CUBEJS_JWT_CLAIMS_NAMESPACE`.
+
+### Custom authentication
+
+Cube allows you to provide your own JWT verification logic. You can use the
+[`check_auth`][ref-config-check-auth] configuration option to verify a JWT and set the security context.
-1. A web server serves an HTML page containing the Cube client, which needs to
- communicate securely with the Cube API.
-2. The web server should generate a JWT with an expiry to achieve this. The
- server could include the token in the HTML it serves or provide the token to
- the frontend via an XHR request, which is then stored it in local storage or
+For example, if you needed to retrieve user information from an LDAP server,
+you might do the following:
+
+```javascript
+module.exports = {
+ checkAuth: async (req, auth) => {
+ try {
+ const userInfo = await getUserFromLDAP(req.get("X-LDAP-User-ID"))
+ return { security_context: userInfo }
+ }
+ catch {
+ throw new Error("Could not authenticate user from LDAP")
+ }
+ }
+}
+```
+
+A typical use case would be:
+
+1. A web server serves a page which needs to communicate with the Cube API.
+2. The web server generates a JWT. The
+ server includes the token in the page or provides the token to
+ the frontend via an XHR request. The token is then stored in the local storage or
a cookie.
-3. The JavaScript client is initialized using this token, and includes it in
- calls to the Cube API.
-4. The token is received by Cube, and verified using any available JWKS (if
- configured)
+3. The token is used for calls to the Cube API.
+4. The token is received by Cube, and verified using any available JWKS (if configured)
5. Once decoded, the token claims are injected into the [security
context][ref-sec-ctx].
@@ -38,7 +108,7 @@ can still use it to [pass a security context][ref-sec-ctx].
-## Generating JSON Web Tokens (JWT)
+### Generating JSON Web Tokens
Authentication tokens are generated based on your API secret. Cube CLI generates
an API Secret when a project is scaffolded and saves this value in the `.env`
@@ -118,7 +188,7 @@ const cubeApi = cube(
You can optionally store this token in local storage or in a cookie, so that you
can then use it to query the Cube API.
-## Using JSON Web Key Sets (JWKS)
+### Using JSON Web Key Sets
@@ -128,8 +198,6 @@ Cognito][ref-recipe-cognito] with Cube.
-### Configuration
-
As mentioned previously, Cube supports verifying JWTs using industry-standard
JWKS. The JWKS can be provided either from a URL, or as a JSON object conforming
to [JWK specification RFC 7517 Section 4][link-jwk-ref], encoded as a string.
@@ -177,7 +245,7 @@ Or configure the same using environment variables:
CUBEJS_JWK_URL=''
```
-### Verifying claims
+#### Verifying claims
Cube can also verify the audience, subject and issuer claims in JWTs. Similarly
to JWK configuration, these can also be configured in the `cube.js`
@@ -201,7 +269,7 @@ CUBEJS_JWT_ISSUER=''
CUBEJS_JWT_SUBJECT=''
```
-### Custom claims namespace
+#### Custom claims namespace
Cube can also extract claims defined in custom namespaces. Simply specify the
namespace in your `cube.js` configuration file:
@@ -214,49 +282,42 @@ module.exports = {
};
```
-### Caching
+## Authentication integration
-Cube caches JWKS by default when
-[`CUBEJS_JWK_URL` or `jwt.jwkUrl` is specified](#configuration).
+When using Cube Cloud, you can enrich the security context with information about
+an authenticated user, obtained during their authentication or loaded via an
+[LDAP integration][ref-ldap-integration].
-- If the response contains a `Cache-Control` header, then Cube uses it to
- determine cache expiry.
-- The keys inside the JWKS are checked for expiry values and used for cache
- expiry.
-- If an inbound request supplies a JWT referencing a key not found in the cache,
- the cache is refreshed.
+
-## Custom authentication
+Authentication integration is available in Cube Cloud on [all product tiers](https://cube.dev/pricing).
-Cube also allows you to provide your own JWT verification logic by setting a
-[`checkAuth()`][ref-config-check-auth] function in the `cube.js` configuration
-file. This function is expected to verify a JWT and return its claims as the
-security context.
+
-As an example, if you needed to retrieve user information from an LDAP server,
-you might do the following:
+You can enable the authentication integration by navigating to the Settings → Configuration
+of your Cube Cloud deployment and using the Enable Cloud Auth Integration toggle.
-```javascript
-module.exports = {
- checkAuth: async (req, auth) => {
- try {
- const userInfo = await getUserFromLDAP(req.get("X-LDAP-User-ID"));
- return { security_context: userInfo };
- } catch {
- throw new Error("Could not authenticate user from LDAP");
- }
- },
-};
-```
-[link-jwt-docs]:
- https://github.com/auth0/node-jsonwebtoken#token-expiration-exp-claim
+[wiki-jwt]: https://en.wikipedia.org/wiki/JSON_Web_Token
+[link-jwt-docs]: https://github.com/auth0/node-jsonwebtoken#token-expiration-exp-claim
[link-jwt-libs]: https://jwt.io/#libraries-io
[link-jwk-ref]: https://tools.ietf.org/html/rfc7517#section-4
-[ref-config-check-auth]: /reference/configuration/config#checkauth
+[ref-config-check-auth]: /reference/configuration/config#check_auth
+[ref-config-jwt]: /reference/configuration/config#jwt
+[ref-config-check-sql-auth]: /reference/configuration/config#check_sql_auth
+[ref-config-can-switch-sql-user]: /reference/configuration/config#can_switch_sql_user
[ref-config-migrate-cube]:
/product/configuration#migration-from-express-to-docker-template
[ref-recipe-auth0]: /guides/recipes/auth/auth0-guide
[ref-recipe-cognito]: /guides/recipes/auth/aws-cognito
[ref-sec-ctx]: /product/auth/context
-[link-slack]: https://slack.cube.dev/
+[ref-apis]: /product/apis-integrations
+[ref-apis-methods]: /product/apis-integrations#authentication-methods
+[ref-rest-api]: /product/apis-integrations/rest-api
+[ref-sql-api]: /product/apis-integrations/sql-api
+[ref-dap]: /product/auth/data-access-policies
+[ref-mls]: /product/auth/member-level-security
+[ref-rls]: /product/auth/row-level-security
+[ref-auth-sso]: /product/workspace/sso
+[ref-ldap-integration]: /product/workspace/sso#ldap-integration
+[ref-cube-cloud-sheets]: /product/apis-integrations/google-sheets
\ No newline at end of file
diff --git a/docs/pages/product/auth/_meta.js b/docs/pages/product/auth/_meta.js
index 9f2bfa9f089e5..68c456f8a9cf7 100644
--- a/docs/pages/product/auth/_meta.js
+++ b/docs/pages/product/auth/_meta.js
@@ -1,3 +1,6 @@
module.exports = {
- "context": "Security context"
+ "context": "Security context",
+ "member-level-security": "Member-level security",
+ "row-level-security": "Row-level security",
+ "data-access-policies": "Data access policies"
}
\ No newline at end of file
diff --git a/docs/pages/product/auth/context.mdx b/docs/pages/product/auth/context.mdx
index 641497f7aee37..7be8ba6b3cdd6 100644
--- a/docs/pages/product/auth/context.mdx
+++ b/docs/pages/product/auth/context.mdx
@@ -31,6 +31,30 @@ inside:
- the [`COMPILE_CONTEXT`][ref-cubes-compile-ctx] global, which is used to
support [multi-tenant deployments][link-multitenancy].
+## Contents
+
+By convention, the contents of the security context should be an object (dictionary)
+with nested structure:
+
+```json
+{
+ "sub": "1234567890",
+ "iat": 1516239022,
+ "user_name": "John Doe",
+ "user_id": 42,
+ "location": {
+ "city": "San Francisco",
+ "state": "CA"
+ }
+}
+```
+
+### Reserved elements
+
+Some features of Cube Cloud (e.g., [authentication integration][ref-auth-integration]
+and [LDAP integration][ref-ldap-integration]) use the `cloud` element in the security context.
+This element is reserved and should not be used for other purposes.
+
## Using query_rewrite
You can use [`query_rewrite`][ref-config-queryrewrite] to amend incoming queries
@@ -223,7 +247,6 @@ def masked(sql, security_context):
return "'--- masked ---'"
```
-
### Usage with pre-aggregations
To generate pre-aggregations that rely on `COMPILE_CONTEXT`, [configure
@@ -248,3 +271,5 @@ build one from a JSON object.
[ref-cubes-compile-ctx]: /reference/data-model/context-variables#compile_context
[ref-devtools-playground]:
/product/workspace/playground#editing-the-security-context
+[ref-auth-integration]: /product/auth#authentication-integration
+[ref-ldap-integration]: /product/workspace/sso#ldap-integration
\ No newline at end of file
diff --git a/docs/pages/product/auth/data-access-policies.mdx b/docs/pages/product/auth/data-access-policies.mdx
new file mode 100644
index 0000000000000..362c4f7c011e0
--- /dev/null
+++ b/docs/pages/product/auth/data-access-policies.mdx
@@ -0,0 +1,164 @@
+# Data access policies
+
+Data access policies provide a holistic mechanism to manage [member-level](#member-level-access)
+and [row-level](#row-level-access) security for different [data access roles](#data-access-roles).
+You can define access control rules in data model files, allowing for an organized
+and maintainable approach to security.
+
+## Data access roles
+
+Each request to Cube includes a [security context][ref-sec-ctx], which can contain
+information about the user. You can use the [`context_to_roles` configuration
+option][ref-ctx-to-roles] to derive the user's roles from the security context:
+
+
+
+```python
+from cube import config
+
+@config('context_to_roles')
+def context_to_roles(ctx: dict) -> list[str]:
+ return ctx['securityContext'].get('roles', ['default'])
+```
+
+```javascript
+module.exports = {
+ contextToRoles: ({ securityContext }) => {
+ return securityContext.roles || ['default']
+ }
+}
+```
+
+
+
+A user can have more than one role.
+
+## Policies
+
+You can define policies that target specific roles and contain member-level and (or)
+row-level security rules:
+
+
+
+```yaml
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ # For all roles, restrict access entirely
+ - role: "*"
+ member_level:
+ includes: []
+
+ # For the `manager` role,
+ # allow access to all members
+ # but filter rows by the user's country
+ - role: manager
+ conditions:
+ - if: "{ securityContext.is_EMEA_based }"
+ member_level:
+ includes: "*"
+ row_level:
+ filters:
+ - member: country
+ operator: eq
+ values: [ "{ securityContext.country }" ]
+```
+
+```javascript
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ // For all roles, restrict access entirely
+ role: `*`,
+ member_level: {
+ includes: []
+ }
+ },
+ {
+ // For the `manager` role,
+ // allow access to all members
+ // but filter rows by the user's country
+ role: `manager`,
+ conditions: [
+ { if: securityContext.is_EMEA_based }
+ ],
+ member_level: {
+ includes: `*`
+ },
+ row_level: {
+ filters: [
+ {
+ member: `country`,
+ operator: `equals`,
+ values: [ securityContext.country ]
+ }
+ ]
+ }
+ }
+ ]
+})
+```
+
+
+
+You can define data access policies both in cubes and views. If you use views,
+it is recommended to keep all your cubes private and define access policies in views only.
+It will make your security rules easier to maintain and reason about, especially
+when it comes to [member-level access](#member-level-access).
+
+For more details on available parameters, check out the [data access policies reference][ref-ref-dap].
+
+## Policy evaluation
+
+When processing a request, Cube will evaluate the data access policies and combine them
+with relevant custom security rules, e.g., [`public` parameters][ref-mls-public] for member-level security
+and [`query_rewrite` filters][ref-rls-queryrewrite] for row-level security.
+
+### Member-level access
+
+Member-level security rules in data access policies are _combined together_
+with `public` parameters of cube and view members using the _AND_ semantics.
+Both will apply to the request.
+
+_When querying a view,_ member-level security rules defined in the view are _**not** combined together_
+with member-level security rules defined in relevant cubes.
+**Only the ones from the view will apply to the request.**
+
+
+
+This is consistent with how column-level security works in SQL databases. If you have
+a view that exposes a subset of columns from a table, it doesnt matter if the
+columns in the table are public or not, the view will expose them anyway.
+
+
+
+### Row-level access
+
+Row-level filters in data access policies are _combined together_ with filters defined
+using the [`query_rewrite` configuration option][ref-config-queryrewrite].
+Both will apply to the request.
+
+_When querying a view,_ row-level filters defined in the view are _combined together_
+with row-level filters defined in relevant cubes. Both will apply to the request.
+
+
+
+This is consistent with how row-level security works in SQL databases. If you have
+a view that exposes a subset of rows from another view, the result set will be
+filtered by the row-level security rules of both views.
+
+
+
+
+[ref-mls]: /product/auth/member-level-security
+[ref-mls-public]: /product/auth/member-level-security#managing-member-level-access
+[ref-rls]: /product/auth/row-level-security
+[ref-rls-queryrewrite]: /product/auth/row-level-security#managing-row-level-access
+[ref-sec-ctx]: /product/auth/context
+[ref-ctx-to-roles]: /reference/configuration/config#context_to_roles
+[ref-ref-dap]: /reference/data-model/data-access-policies
+[ref-config-queryrewrite]: /reference/configuration/config#query_rewrite
\ No newline at end of file
diff --git a/docs/pages/product/data-modeling/concepts/publicity.mdx b/docs/pages/product/auth/member-level-security.mdx
similarity index 68%
rename from docs/pages/product/data-modeling/concepts/publicity.mdx
rename to docs/pages/product/auth/member-level-security.mdx
index 7d5d7f625fba3..2e469ed845c66 100644
--- a/docs/pages/product/data-modeling/concepts/publicity.mdx
+++ b/docs/pages/product/auth/member-level-security.mdx
@@ -1,21 +1,25 @@
-# Publicity of data model entities
+# Member-level security
-The data model serves as a facade of your data and enables running
-[queries][ref-queries] via a [rich set of APIs][ref-apis] by referencing data
-model [entities][ref-data-modeling-concepts]: cubes, views, and their members.
-Controlling whether they are public or not helps manage data access and expose
-a coherent representation of the data model to end users.
+The data model serves as a facade of your data. With member-level security,
+you can define whether [data model entities][ref-data-modeling-concepts] (cubes, views,
+and their members) are exposed to end users and can be queried via [APIs &
+integrations][ref-apis].
-By default, all cubes, views, measures, dimensions, and segments are *public*,
-meaning that they can be used in API queries and they are visible during data
-model introspection.
+Member-level security in Cube is similar to column-level security in SQL databases.
+Defining whether users have access to [cubes][ref-cubes] and [views][ref-views] is
+similar to defining access to database tables; defining whether they have access
+to dimensions and measures — to columns.
-## Managing publicity
+__By default, all cubes, views, and their members are *public*,__ meaning that they
+can be accessed by any users and they are also visible during data model introspection.
+
+## Managing member-level access
You can explicitly make a data model entity public or private by setting its
`public` parameter to `true` or `false`. This parameter is available for
[cubes][ref-cubes-public], [views][ref-views-public], [measures][ref-measures-public],
-[dimensions][ref-dimensions-public], and [segments][ref-segments-public].
+[dimensions][ref-dimensions-public], [hierarchies][ref-hierarchies-public], and
+[segments][ref-segments-public].
@@ -56,6 +60,16 @@ anyway, you can use the [`query_rewrite` configuration option][ref-query-rewrite
## Best practices
+### Data access policies
+
+You can use [data access policies][ref-dap] to manage both member-level and
+[row-level][ref-rls] security for different roles. With them, you can keep
+access control rules in one place instead of spreading them across a number of
+`public` parameters in a cube or a view.
+
+__It is recommended to use data access policies by default.__ You can also combine
+them with setting some `public` parameters manually for specific cases.
+
### Cubes and views
If your data model contains both [cubes][ref-cubes] and [views][ref-views],
@@ -116,11 +130,11 @@ cube(`users`, {
[ref-data-modeling-concepts]: /product/data-modeling/concepts
[ref-apis]: /product/apis-integrations
-[ref-queries]: /product/apis-integrations/queries
[ref-cubes-public]: /reference/data-model/cube#public
[ref-views-public]: /reference/data-model/view#public
[ref-measures-public]: /reference/data-model/measures#public
[ref-dimensions-public]: /reference/data-model/dimensions#public
+[ref-hierarchies-public]: /reference/data-model/hierarchies#public
[ref-segments-public]: /reference/data-model/segments#public
[ref-cubes]: /product/data-modeling/concepts#cubes
[ref-views]: /product/data-modeling/concepts#views
@@ -129,4 +143,6 @@ cube(`users`, {
[ref-dynamic-data-modeling]: /product/data-modeling/dynamic
[ref-query-rewrite]: /reference/configuration/config#query_rewrite
[ref-dev-mode]: /product/configuration#development-mode
-[ref-playground]: /product/workspace/playground
\ No newline at end of file
+[ref-playground]: /product/workspace/playground
+[ref-dap]: /product/auth/data-access-policies
+[ref-rls]: /product/auth/row-level-security
\ No newline at end of file
diff --git a/docs/pages/product/auth/row-level-security.mdx b/docs/pages/product/auth/row-level-security.mdx
new file mode 100644
index 0000000000000..d5c149cf42dbf
--- /dev/null
+++ b/docs/pages/product/auth/row-level-security.mdx
@@ -0,0 +1,46 @@
+# Row-level security
+
+The data model serves as a facade of your data. With row-level security,
+you can define whether some [data model][ref-data-modeling-concepts] facts are exposed
+to end users and can be queried via [APIs & integrations][ref-apis].
+
+Row-level security in Cube is similar to row-level security in SQL databases.
+Defining whether users have access to specific facts from [cubes][ref-cubes] and
+[views][ref-views] is similar to defining access to rows in database tables.
+
+__By default, all rows are *public*,__ meaning that no filtering is applied to
+data model facts when they are accessed by any users.
+
+## Managing row-level access
+
+You can implement row-level access control by applying additional filters conditionally
+in the [`query_rewrite` configuration option][ref-query-rewrite].
+
+### Dynamic data models
+
+You can implement row-level access control at the data model level
+[dynamically][ref-dynamic-data-modeling] by adjusting the [`sql` parameter][ref-cubes-sql]
+of cubes.
+
+## Best practices
+
+### Data access policies
+
+You can use [data access policies][ref-dap] to manage both [member-level][ref-mls]
+and row-level security for different roles. With them, you can define access control
+rules in data model files instead of mixing them together in a single block of code
+in `query_rewrite`.
+
+__It is recommended to use data access policies by default.__ You can also combine
+them with using your own code in `query_rewrite` for specific cases.
+
+
+[ref-data-modeling-concepts]: /product/data-modeling/concepts
+[ref-apis]: /product/apis-integrations
+[ref-cubes]: /product/data-modeling/concepts#cubes
+[ref-views]: /product/data-modeling/concepts#views
+[ref-cubes-sql]: /reference/data-model/cube#sql
+[ref-dynamic-data-modeling]: /product/data-modeling/dynamic
+[ref-query-rewrite]: /reference/configuration/config#query_rewrite
+[ref-dap]: /product/auth/data-access-policies
+[ref-mls]: /product/auth/member-level-security
\ No newline at end of file
diff --git a/docs/pages/product/configuration.mdx b/docs/pages/product/configuration.mdx
index a8a196acae343..990706bee4110 100644
--- a/docs/pages/product/configuration.mdx
+++ b/docs/pages/product/configuration.mdx
@@ -152,8 +152,7 @@ Cube can be run in an insecure, development mode by setting the
mode does the following:
- Disables authentication checks.
-- Disables access control checks based on the [publicity][ref-data-model-publicity]
-of data model entities.
+- Disables [member-level access control][ref-mls].
- Enables Cube Store in single instance mode.
- Enables background refresh for in-memory cache and [scheduled
pre-aggregations][link-scheduled-refresh].
@@ -177,6 +176,6 @@ of data model entities.
[ref-dynamic-data-models]: /product/data-modeling/dynamic
[ref-custom-docker-image]: /product/deployment/core#extend-the-docker-image
[link-docker-env-vars]: https://docs.docker.com/compose/environment-variables/set-environment-variables/
-[ref-data-model-publicity]: /product/data-modeling/concepts/publicity
+[ref-mls]: /product/auth/member-level-security
[link-current-python-version]: https://github.com/cube-js/cube/blob/master/packages/cubejs-docker/latest.Dockerfile#L13
[link-current-nodejs-version]: https://github.com/cube-js/cube/blob/master/packages/cubejs-docker/latest.Dockerfile#L1
\ No newline at end of file
diff --git a/docs/pages/product/data-modeling/concepts.mdx b/docs/pages/product/data-modeling/concepts.mdx
index 2cb3282c1215c..e05b4faa817b2 100644
--- a/docs/pages/product/data-modeling/concepts.mdx
+++ b/docs/pages/product/data-modeling/concepts.mdx
@@ -34,7 +34,7 @@ We'll use a sample e-commerce database with two tables, `orders` and
## Cubes
-A [cube][ref-cubes] represents a dataset in Cube, and is conceptually similar to a [view in
+_Cubes_ represent datasets in Cube and are conceptually similar to [views in
SQL][wiki-view-sql]. Cubes are usually declared in separate files with one
cube per file. Typically, a cube points to a single table in
your database using the [`sql_table` property][ref-schema-ref-sql-table]:
@@ -82,15 +82,18 @@ cubes:
-Within each cube are definitions of [dimensions][self-dimensions],
-[measures][self-measures], and [segments](#segments). [Joins](#joins) are used
-to define relations between cubes; [pre-aggregations](#pre-aggregations) are
-designed to accelerate queries to cubes.
+Each cube contains the definitions of its _members_: [dimensions](#dimensions),
+[measures](#measures), and [segments](#segments). You can control the access to
+cubes and their members by configuring the [member-level security][ref-mls].
+
+[Joins](#joins) are used to define relations between cubes.
+[Pre-aggregations](#pre-aggregations) are used to accelerate queries to cubes.
+Cubes and their members can be further referenced by [views](#views).
Note that cubes support [extension][ref-extending-cubes],
[polymorphism][ref-polymorphic-cubes], and [data blending][ref-data-blending].
-Also, cubes should not necessarily be defined statically; you can actually build
-[dynamic data models][ref-dynamic-data-models].
+Cubes can be defined statically and you can also build [dynamic data
+models][ref-dynamic-data-models].
@@ -100,18 +103,24 @@ For massive [multi-tenancy][ref-multitenancy] configurations, e.g., with more th
+
+
+See the reference documentaton for the full list of cube [parameters][ref-cubes].
+
+
+
## Views
-Views sit on top of the data graph of cubes and create a facade of your whole
+_Views_ sit on top of the data graph of cubes and create a facade of your whole
data model with which data consumers can interact. They are useful for defining
metrics, managing governance and data access, and controlling ambiguous join
paths.
-Views can **not** have their own members. Instead, they use the `cubes`
-parameter to include members of cubes. Optionally, you can also group members of a view
-into [folders][ref-ref-folders].
+Views do **not** define their own members. Instead, they reference cubes by
+specific join paths and include their members. Optionally, you can also group
+members of a view into [folders][ref-ref-folders].
In the example below, we create the `orders` view which includes select members
from `base_orders`, `products`, and `users` cubes:
@@ -182,12 +191,18 @@ views:
Views do **not** define any [pre-aggregations](#pre-aggregations). Instead,
they [reuse][ref-matching-preaggs] pre-aggregations from underlying cubes.
-View may not only be defined statically; you can actually build
-[dynamic data models][ref-dynamic-data-models].
+View can be defined statically and you can also build [dynamic data
+models][ref-dynamic-data-models].
+
+
+
+See the reference documentaton for the full list of view [parameters][ref-views].
+
+
## Dimensions
-Dimensions represent the properties of a **single** data point in the cube.
+_Dimensions_ represent the properties of a **single** data point in the cube.
[The `orders` table](#top) contains only dimensions, so representing them in the
`orders` cube is straightforward:
@@ -289,10 +304,29 @@ Also, [proxy dimensions][ref-proxy-dimensions] are helpful for code reusability
and [subquery dimensions][ref-subquery-dimensions] can be used to join cubes
implicitly.
+
+
+See the reference documentaton for the full list of [dimension parameters][ref-dimensions].
+
+
+
### Dimension types
-Dimensions can be of different types. See the [dimension type
-reference][ref-schema-dimension-types] for details.
+Dimensions can be of different types, e.g., `string`, `number`, or `time`. Often,
+data types in SQL are mapped to dimension types in the following way:
+
+| Data type in SQL | Dimension type in Cube |
+| --- | --- |
+| `timestamp`, `date`, `time` | [`time`](/reference/data-model/types-and-formats#time-1) |
+| `text`, `varchar` | [`string`](/reference/data-model/types-and-formats#string-1) |
+| `integer`, `bigint`, `decimal` | [`number`](/reference/data-model/types-and-formats#number-1) |
+| `boolean` | [`boolean`](/reference/data-model/types-and-formats#boolean-1) |
+
+
+
+See the [dimension type reference][ref-ref-dimension-types] for details.
+
+
### Time dimensions
@@ -377,7 +411,7 @@ Time dimensions are essential to enabling performance boosts such as
## Measures
-Measures represent the properties of a **set of data points** in the cube. To
+_Measures_ represent the properties of a **set of data points** in the cube. To
add a measure called `count` to our `orders` cube, for example, we can do the
following:
@@ -438,15 +472,19 @@ cubes:
-Also, [calculated measures][ref-calculated-measures] can be used to perform calculations
-on other measures.
+[Calculated measures][ref-calculated-measures] and [subquery dimensions][ref-subquery-dimensions]
+can be used for measure composition.
-### Measure types
+
-Measures can be of different types. See the [measure type
-reference][ref-schema-measure-types] for details.
+See the reference documentaton for the full list of measure [parameters][ref-measures].
-Often, aggregate functions in SQL are mapped to measure types in the following way:
+
+
+### Measure types
+
+Measures can be of different types, e.g., `count`, `sum`, or `number`. Often,
+aggregate functions in SQL are mapped to measure types in the following way:
| Aggregate function in SQL | Measure type in Cube |
| --- | --- |
@@ -462,6 +500,12 @@ Often, aggregate functions in SQL are mapped to measure types in the following w
| `SUM` | [`sum`](/reference/data-model/types-and-formats#sum) |
| Any function returning a timestamp, e.g., `MAX(time)` | [`time`](/reference/data-model/types-and-formats#time) |
+
+
+See the [measure type reference][ref-ref-measure-types] for details.
+
+
+
### Measure additivity
Additivity is a property of measures that detemines whether measure values,
@@ -578,7 +622,7 @@ an impact on [pre-aggregation matching][ref-matching-preaggs].
## Joins
-Joins define the relationships between cubes, which then allows accessing and
+_Joins_ define the relationships between cubes, which then allows accessing and
comparing properties from two or more cubes at the same time. In Cube, all joins
are `LEFT JOIN`s.
@@ -624,15 +668,22 @@ cubes:
-There are three [types of join relationships][ref-schema-ref-joins-types]
+There are three [types of join relationships][ref-ref-join-types]
(`one_to_one`, `one_to_many`, and `many_to_one`) and a few [other
-concepts][ref-working-with-joins].
+concepts][ref-working-with-joins] such as the direction of joins and trasitive
+joins pitfalls.
+
+
+
+See the reference documentaton for the full list of join [parameters][ref-joins].
+
+
## Segments
-Segments are filters that are predefined in the data model instead of [a Cube
-query][ref-backend-query-filters]. They allow simplifying Cube queries and make
-it easy to re-use common filters across a variety of queries.
+_Segments_ are pre-defined filters that are kept within the data model instead of
+[a Cube query][ref-backend-query-filters]. They help to simplify queries and make
+it easy to reuse common filters across a variety of queries.
To add a segment which limits results to completed orders, we can do the
following:
@@ -663,11 +714,17 @@ cubes:
+
+
+See the reference documentaton for the full list of segment [parameters][ref-segments].
+
+
+
## Pre-aggregations
-Pre-aggregations are a powerful way of caching frequently-used, expensive
-queries and keeping the cache up-to-date on a periodic basis. Within a data
-model, they are defined under the `pre_aggregations` property:
+_Pre-aggregations_ provide a powerful way to accelerate frequently used queries
+and keep the cache up-to-date. Within a data model, they are defined using the
+`pre_aggregations` property:
@@ -706,31 +763,41 @@ cubes:
A more thorough introduction can be found in [Getting Started with
Pre-Aggregations][ref-caching-preaggs-intro].
+
+
+See the reference documentaton for the full list of pre-aggregation
+[parameters][ref-preaggs].
+
+
+
+
[ref-backend-query-filters]:
/product/apis-integrations/rest-api/query-format#filters-format
[ref-caching-preaggs-intro]: /product/caching/getting-started-pre-aggregations
[ref-caching-use-preaggs-partition-time]:
/product/caching/using-pre-aggregations#partitioning
-[ref-schema-dimension-types]:
- /reference/data-model/types-and-formats#dimension-types
-[ref-schema-measure-types]:
- /reference/data-model/types-and-formats#measure-types
-[ref-schema-ref-joins-types]:
- /reference/data-model/joins#relationship
+[ref-ref-dimension-types]: /reference/data-model/types-and-formats#dimension-types
+[ref-ref-measure-types]: /reference/data-model/types-and-formats#measure-types
+[ref-ref-join-types]: /reference/data-model/joins#relationship
[ref-schema-ref-sql]: /reference/data-model/cube#sql
[ref-schema-ref-sql-table]: /reference/data-model/cube#sql_table
[ref-tutorial-incremental-preagg]:
/reference/data-model/pre-aggregations#incremental
[ref-cubes]: /reference/data-model/cube
+[ref-views]: /reference/data-model/view
+[ref-dimensions]: /reference/data-model/dimensions
+[ref-measures]: /reference/data-model/measures
+[ref-joins]: /reference/data-model/joins
+[ref-segments]: /reference/data-model/segments
+[ref-preaggs]: /reference/data-model/pre-aggregations
[ref-extending-cubes]: /product/data-modeling/concepts/code-reusability-extending-cubes
[ref-polymorphic-cubes]: /product/data-modeling/concepts/polymorphic-cubes
[ref-data-blending]: /product/data-modeling/concepts/data-blending
[ref-dynamic-data-models]: /product/data-modeling/dynamic
[ref-proxy-dimensions]: /product/data-modeling/concepts/calculated-members#proxy-dimensions
[ref-subquery-dimensions]: /product/data-modeling/concepts/calculated-members#subquery-dimensions
+[ref-calculated-measures]: /product/data-modeling/concepts/calculated-members#calculated-measures
[ref-working-with-joins]: /product/data-modeling/concepts/working-with-joins
-[self-dimensions]: #dimensions
-[self-measures]: #measures
[wiki-olap]: https://en.wikipedia.org/wiki/Online_analytical_processing
[wiki-view-sql]: https://en.wikipedia.org/wiki/View_(SQL)
[ref-matching-preaggs]: /product/caching/matching-pre-aggregations
@@ -744,5 +811,6 @@ Pre-Aggregations][ref-caching-preaggs-intro].
[ref-ref-primary-key]: /reference/data-model/dimensions#primary_key
[ref-custom-granularity-recipe]: /guides/recipes/data-modeling/custom-granularity
[ref-proxy-granularity]: /product/data-modeling/concepts/calculated-members#time-dimension-granularity
+[ref-mls]: /product/auth/member-level-security
[ref-ref-hierarchies]: /reference/data-model/hierarchies
[ref-ref-folders]: /reference/data-model/view#folders
\ No newline at end of file
diff --git a/docs/pages/product/data-modeling/concepts/_meta.js b/docs/pages/product/data-modeling/concepts/_meta.js
index 5ee99fa7eda18..27e102e8ed734 100644
--- a/docs/pages/product/data-modeling/concepts/_meta.js
+++ b/docs/pages/product/data-modeling/concepts/_meta.js
@@ -1,5 +1,4 @@
module.exports = {
- "publicity": "Publicity",
"calculated-members": "Calculated members",
"code-reusability-extending-cubes": "Extending cubes",
"polymorphic-cubes": "Polymorphic cubes",
diff --git a/docs/pages/product/workspace/_meta.js b/docs/pages/product/workspace/_meta.js
index 0b05eebdbebe8..6e324c427cec5 100644
--- a/docs/pages/product/workspace/_meta.js
+++ b/docs/pages/product/workspace/_meta.js
@@ -13,7 +13,7 @@ module.exports = {
"performance": "Performance Insights",
"monitoring": "Monitoring Integrations",
"access-control": "Access Control",
- "sso": "Single Sign-on",
+ "sso": "Authentication & SSO",
"audit-log": "Audit Log",
"encryption-keys": "Encryption keys",
"budgets": "Budgets",
diff --git a/docs/pages/product/workspace/sso.mdx b/docs/pages/product/workspace/sso.mdx
index 151f6e5f77698..58d99656b4214 100644
--- a/docs/pages/product/workspace/sso.mdx
+++ b/docs/pages/product/workspace/sso.mdx
@@ -1,22 +1,20 @@
----
-redirect_from:
- - /workspace/sso/
----
+# Authentication & SSO
-# Single Sign-on
-
-As an account administrator, you can manage how your team accesses Cube Cloud.
-There are options to log in using email and password, a GitHub account, or a
-Google account.
+As an account administrator, you can manage how your team and users access Cube Cloud.
+You can authenticate using email and password, a GitHub account, or a Google account.
Cube Cloud also provides single sign-on (SSO) via identity providers supporting
-industry-proven [SAML 2.0 protocol][wiki-saml], e.g., Okta, Google Workspace,
-Azure AD, etc.
+[SAML 2.0](#saml-20), e.g., Okta, Google Workspace, Azure AD, etc.
+
+Finally, Cube Cloud provides the [LDAP integration](#ldap-integration), enabling
+users of [APIs & integrations][ref-apis] to authenticate via an LDAP catalog
+and assume roles that work with [data access policies][ref-dap] once [authentication
+integration][ref-auth-integration] is enabled.
-Single sign-on is available in Cube Cloud on
-[Enterprise and above](https://cube.dev/pricing) product tiers.
+Authentication is available in Cube Cloud on [all product tiers](https://cube.dev/pricing).
+[SAML 2.0](#saml-20) and [LDAP integration](#ldap-integration) are available on [Enterprise and above](https://cube.dev/pricing) product tiers.
@@ -25,10 +23,23 @@ Single sign-on is available in Cube Cloud on
style="border: 0;"
/>
-## Guides
+## Configuration
+
+To manage authentication settings, navigate to Team & Security settings
+of your Cube Cloud account, and switch to the Authentication & SSO tab:
+
+
+
+Use the toggles in Password, Google, and GitHub
+sections to enable or disable these authentication options.
+
+### SAML 2.0
+
+Use the toggle in the SAML 2.0 section to enable or disable the authentication
+via an identity provider supporting the [SAML 2.0 protocol][wiki-saml].
+Once it's enabled, you'll see the SAML 2.0 Settings section directly below.
-Single sign-on works with various identity providers. Check the following guides
-to get tool-specific instructions:
+Check the following guides to get tool-specific instructions on configuration:
-## Configuration
+### LDAP integration
-To manage sign-in and single sign-on settings, click your user name from the
-top-right corner, navigate to Team & Security, and switch to
-the Authentication & SSO tab:
+Use the toggle in the LDAP Integration section to enable or disable the
+integration with an [LDAP catalog][wiki-ldap].
+Once it's enabled, you'll see the LDAP Settings section directly below.
-
+
+
+Cube Cloud will be accessing your LDAP server from the IP addresses shown under
+LDAP Settings. If needed, add these IP addresses to an allowlist.
+
+
+
+You can configure [connection settings](#connection-settings) and use the
+Test Connection button to validate them. You can also configure
+[user properties](#user-properties-mapping) mapping, [user roles](#user-roles-mapping) mapping,
+and [user attributes](#user-attributes-mapping) mapping.
+
+#### Connection settings
+
+You have to configure the following connection settings:
+
+| Option | Description |
+| --- | --- |
+| LDAP Server URL | Address of your LDAP server |
+| Use Secure LDAP | Use an encrypted connection (LDAPS) |
+| Don't Verify CA | Disable certificate authority verification |
+| Certificate | Certificate for LDAPS in the PEM format |
+| Certificate Authority | Certificate for the private CA in the PEM format |
+| Key | Key for mutual TLS (mTLS) in the PEM format |
+| Bind DN | User name for LDAP authentication |
+| Bind Credentials | Password for LDAP authentication |
+| Search Base | Base DN for searching users |
+| User Object Class | Object class for user entries |
+
+Use the tooltips in Cube Cloud to get more information about each setting.
+
+#### User properties mapping
+
+You have to configure how user data in an LDAP catalog maps to user properties in Cube Cloud.
+The following properties are required:
+
+| Property | Description |
+| --- | --- |
+| Login Attribute | Login name |
+| Id Attribute | Unique identifier |
+| Email Attribute | Email address |
+| Name Attribute | Full name |
+
+Use the tooltips in Cube Cloud to get more information about each setting.
+
+#### User roles mapping
+
+You can configure how user data in an LDAP catalog maps to roles in Cube Cloud.
+You can also use mapped roles with [data access policies][ref-dap] once [authentication
+integration][ref-auth-integration] is enabled.
+
+Mapping is performed as follows:
+* Roles Attribute is retrieved from an LDAP catalog.
+* Retrieved value is transformed using rules under Role mapping.
+* If the value matches an existing role in Cube Cloud, then the user assumes this role.
+
+Additionally, the user always assumes the role specified under Default Cloud role.
+
+
+
+All roles will be available under `cubeCloud.roles` array in the [security context][ref-security-context]:
+
+```json
+{
+ "cubeCloud": {
+ "roles": [
+ "Everyone",
+ "manager"
+ ]
+ }
+}
+```
+
+#### User attributes mapping
+
+You can also bring more user data from an LDAP catalog to use with [data access policies][ref-dap].
+Mapping is performed using the rules under Attribute mapping.
+
+All mapped attributes and their values will be available under `cubeCloud.userAttributes`
+dictionary in the [security context][ref-security-context]:
+
+```json
+{
+ "cubeCloud": {
+ "userAttributes": {
+ "fullName": "John Doe",
+ "department": "Finance",
+ "location": "San Mateo"
+ }
+ }
+}
+```
[wiki-saml]: https://en.wikipedia.org/wiki/SAML_2.0
+[wiki-ldap]: https://en.wikipedia.org/wiki/Lightweight_Directory_Access_Protocol
+[ref-apis]: /product/apis-integrations
+[ref-dap]: /product/auth/data-access-policies
+[ref-security-context]: /product/auth/context
+[ref-auth-integration]: /product/auth#authentication-integration
\ No newline at end of file
diff --git a/docs/pages/reference/configuration/config.mdx b/docs/pages/reference/configuration/config.mdx
index b9abd79237c33..36a70e231969d 100644
--- a/docs/pages/reference/configuration/config.mdx
+++ b/docs/pages/reference/configuration/config.mdx
@@ -52,8 +52,6 @@ environment variable. The default value is `model`.
Use [`repositoryFactory`][self-repofactory] for [multitenancy][ref-multitenancy]
or when a more flexible setup is needed.
-{/* TODO: https://cubedevinc.atlassian.net/browse/CC-3095 */}
-
### `context_to_app_id`
It's a [multitenancy][ref-multitenancy] option.
@@ -1308,11 +1306,64 @@ module.exports = {
+### `context_to_roles`
+
+Used by [data access policies][ref-dap]. This option is used to derive a list of
+[data access roles][ref-dap-roles] from the [security context][ref-sec-ctx].
+
+
+
+```python
+from cube import config
+
+@config('context_to_roles')
+def context_to_roles(ctx: dict) -> list[str]:
+ return ctx['securityContext'].get('roles', ['default'])
+```
+
+```javascript
+
+module.exports = {
+ contextToRoles: ({ securityContext }) => {
+ return securityContext.roles || ['default']
+ }
+}
+```
+
+
+
+If the [user roles mapping][ref-ldap-roles-mapping] in the [LDAP integration][ref-ldap-integration]
+is configured and the [authentication integration][ref-auth-integration] is enabled,
+the `context_to_roles` option might be defined as follows:
+
+
+
+```python
+from cube import config
+
+@config('context_to_roles')
+def context_to_roles(ctx: dict) -> list[str]:
+ cloud_ctx = ctx['securityContext'].get('cloud', {'roles': []})
+ return cloud_ctx.get('roles', [])
+```
+
+```javascript
+
+module.exports = {
+ contextToRoles: ({ securityContext }) => {
+ const cloud_ctx = securityContext.cloud || { roles: [] }
+ return cloud_ctx.roles || []
+ }
+}
+```
+
+
+
## Utility
### `logger`
-A function to server as a custom logger.
+A function to define a custom logger.
Accepts the following arguments:
- `message`: the message to be logged
@@ -1439,4 +1490,9 @@ If not defined, Cube will lookup for environment variable
[link-snake-case]: https://en.wikipedia.org/wiki/Snake_case
[link-camel-case]: https://en.wikipedia.org/wiki/Camel_case
[link-github-cube-drivers]: https://github.com/cube-js/cube/tree/master/packages
-[ref-ungrouped-query]: /product/apis-integrations/queries#ungrouped-query
\ No newline at end of file
+[ref-ungrouped-query]: /product/apis-integrations/queries#ungrouped-query
+[ref-dap]: /product/auth/data-access-policies
+[ref-dap-roles]: /product/auth/data-access-policies#data-access-roles
+[ref-auth-integration]: /product/auth#authentication-integration
+[ref-ldap-roles-mapping]: /product/workspace/sso#user-roles-mapping
+[ref-ldap-integration]: /product/workspace/sso#ldap-integration
\ No newline at end of file
diff --git a/docs/pages/reference/data-model/_meta.js b/docs/pages/reference/data-model/_meta.js
index 781d8f47f4df7..66735c5ec41c5 100644
--- a/docs/pages/reference/data-model/_meta.js
+++ b/docs/pages/reference/data-model/_meta.js
@@ -7,6 +7,7 @@ module.exports = {
"segments": "Segments",
"joins": "Joins",
"pre-aggregations": "Pre-aggregations",
+ "data-access-policies": "Data access policies",
"types-and-formats": "Types and formats",
"context-variables": "Context variables"
}
\ No newline at end of file
diff --git a/docs/pages/reference/data-model/cube.mdx b/docs/pages/reference/data-model/cube.mdx
index 24ee25cd3a71e..eec0b4420d2fd 100644
--- a/docs/pages/reference/data-model/cube.mdx
+++ b/docs/pages/reference/data-model/cube.mdx
@@ -12,7 +12,7 @@ Cubes are typically declared in separate files with one cube per file.
Within each cube are definitions of [measures][ref-ref-measures],
[dimensions][ref-ref-dimensions], [hierarchies][ref-ref-hierarchies],
[segments][ref-ref-segments], [joins][ref-ref-joins] between cubes,
-and [pre-aggregations][ref-ref-pre-aggs].
+[pre-aggregations][ref-ref-pre-aggs], and [data access policies][ref-ref-dap].
@@ -110,88 +110,31 @@ cubes:
-### `data_source`
+### `sql_alias`
-Each cube can have its own `data_source` name to support scenarios where data
-should be fetched from multiple databases. The value of the `data_source`
-parameter will be passed to the [`driverFactory()`][ref-config-driverfactory]
-function as part of the `context` parameter. By default, each cube has a
-`default` value for its `data_source`; to override it you can use:
+Use `sql_alias` when auto-generated cube alias prefix is too long and truncated
+by databases such as Postgres:
```javascript
-cube(`order_facts`, {
- data_source: `prod_db`,
+cube(`order_facts_about_literally_everything_in_the_world`, {
sql_table: `orders`,
+ sql_alias: `order_facts`,
});
```
```yaml
cubes:
- - name: order_facts
- data_source: prod_db
+ - name: order_facts_about_literally_everything_in_the_world
sql_table: orders
+ sql_alias: order_facts
```
-### `description`
-
-This parameter provides a human-readable description of a cube.
-When applicable, it will be displayed in [Playground][ref-playground] and exposed
-to data consumers via [APIs and integrations][ref-apis].
-
-A description can give a hint both to your team and end users, making sure they
-interpret the data correctly.
-
-
-
-```javascript
-cube(`orders`, {
- sql_table: `orders`,
- title: `Product Orders`,
- description: `All orders-related information`,
-});
-```
-
-```yaml
-cubes:
- - name: orders
- sql_table: orders
- title: Product Orders
- description: All orders-related information
-```
-
-
-
-### `meta`
-
-Custom metadata. Can be used to pass any information to the frontend.
-
-
-
-```javascript
-cube(`orders`, {
- sql_table: `orders`,
- title: `Product Orders`,
- meta: {
- any: `value`
- }
-});
-```
-
-```yaml
-cubes:
- - name: orders
- sql_table: orders
- title: Product Orders
- meta:
- any: value
-
-```
-
-
+It'll generate aliases for members such as `order_facts__count`. `sql_alias` affects
+all member names including pre-aggregation table names.
### `extends`
@@ -276,6 +219,151 @@ cube(`extended_order_facts`, {
});
```
+### `data_source`
+
+Each cube can have its own `data_source` name to support scenarios where data
+should be fetched from multiple databases. The value of the `data_source`
+parameter will be passed to the [`driverFactory()`][ref-config-driverfactory]
+function as part of the `context` parameter. By default, each cube has a
+`default` value for its `data_source`; to override it you can use:
+
+
+
+```javascript
+cube(`order_facts`, {
+ data_source: `prod_db`,
+ sql_table: `orders`,
+});
+```
+
+```yaml
+cubes:
+ - name: order_facts
+ data_source: prod_db
+ sql_table: orders
+```
+
+
+
+### `sql`
+
+The `sql` parameter specifies the SQL that will be used to generate a table that
+will be queried by a cube. It can be any valid SQL query, but usually it takes
+the form of a `SELECT * FROM my_table` query. Please note that you don't need to
+use `GROUP BY` in a SQL query on the cube level. This query should return a
+plain table, without aggregations.
+
+
+
+```javascript
+cube(`orders`, {
+ sql: `SELECT * FROM orders`,
+});
+```
+
+```yaml
+cubes:
+ - name: orders
+ sql: SELECT * FROM orders
+```
+
+
+
+With JavaScript models, you can also reference other cubes' SQL statements for
+code reuse:
+
+```javascript
+cube(`companies`, {
+ sql: `
+ SELECT users.company_name, users.company_id
+ FROM ${users.sql()} AS users
+ `,
+});
+```
+
+It is recommended to prefer the [`sql_table`](#parameters-sql-table) parameter
+over the `sql` parameter for all cubes that are supposed to use queries like
+this: `SELECT * FROM table`.
+
+### `sql_table`
+
+The `sql_table` parameter is used as a concise way for defining a cube that uses
+a query like this: `SELECT * FROM table`. Instead of using the
+[`sql`](#parameters-sql) parameter, use `sql_table` with the table name that this
+cube will query.
+
+
+
+```javascript
+cube(`orders`, {
+ sql_table: `public.orders`,
+});
+```
+
+```yaml
+cubes:
+ - name: orders
+ sql_table: public.orders
+```
+
+
+
+### `title`
+
+Use `title` to change the display name of the cube. By default, Cube will
+humanize the cube's name, so for instance, `users_orders` would become
+`Users Orders`. If default humanizing doesn't work in your case, please use the
+title parameter. It is highly recommended to give human readable names to your
+cubes. It will help everyone on a team better understand the data structure and
+will help maintain a consistent set of definitions across an organization.
+
+
+
+```javascript
+cube(`orders`, {
+ sql_table: `orders`,
+ title: `Product Orders`,
+});
+```
+
+```yaml
+cubes:
+ - name: orders
+ sql_table: orders
+ title: Product Orders
+```
+
+
+
+### `description`
+
+This parameter provides a human-readable description of a cube.
+When applicable, it will be displayed in [Playground][ref-playground] and exposed
+to data consumers via [APIs and integrations][ref-apis].
+
+A description can give a hint both to your team and end users, making sure they
+interpret the data correctly.
+
+
+
+```javascript
+cube(`orders`, {
+ sql_table: `orders`,
+ title: `Product Orders`,
+ description: `All orders-related information`,
+});
+```
+
+```yaml
+cubes:
+ - name: orders
+ sql_table: orders
+ title: Product Orders
+ description: All orders-related information
+```
+
+
+
### `public`
The `public` parameter is used to manage the visibility of a cube. Valid values
@@ -318,7 +406,7 @@ The default values for `refresh_key` are
Refresh key of a query is a concatenation of all cubes refresh keys involved in
query. For rollup queries pre-aggregation table name is used as a refresh key.
-You can set up a custom refresh check SQL by changing `refresh_key` property.
+You can set up a custom refresh check SQL by changing the `refresh_key` parameter.
Often, a `MAX(updated_at_timestamp)` for OLTP data is a viable option, or
examining a metadata table for whatever system is managing the data to see when
it last ran. timestamp in that case.
@@ -374,7 +462,7 @@ cubes:
`every` - can be set as an interval with granularities `second`, `minute`,
`hour`, `day`, and `week` or accept CRON string with some limitations. If you
-set `every` as CRON string, you can use the `timezone` property.
+set `every` as CRON string, you can use the `timezone` parameter.
For example:
@@ -462,121 +550,61 @@ SELECT FLOOR(EXTRACT(EPOCH FROM NOW()) / 5)
└───────────────────────── second (0 - 59, optional)
```
-### `sql`
+### `meta`
-The `sql` parameter specifies the SQL that will be used to generate a table that
-will be queried by a cube. It can be any valid SQL query, but usually it takes
-the form of a `SELECT * FROM my_table` query. Please note that you don't need to
-use `GROUP BY` in a SQL query on the cube level. This query should return a
-plain table, without aggregations.
+Custom metadata. Can be used to pass any information to the frontend.
```javascript
cube(`orders`, {
- sql: `SELECT * FROM orders`,
+ sql_table: `orders`,
+ title: `Product Orders`,
+ meta: {
+ any: `value`
+ }
});
```
```yaml
cubes:
- name: orders
- sql: SELECT * FROM orders
-```
-
-
-
-With JavaScript models, you can also reference other cubes' SQL statements for
-code reuse:
-
-```javascript
-cube(`companies`, {
- sql: `
- SELECT users.company_name, users.company_id
- FROM ${users.sql()} AS users
- `,
-});
-```
-
-It is recommended to prefer the [`sql_table`](#parameters-sql-table) property
-over the `sql` property for all cubes that are supposed to use queries like
-this: `SELECT * FROM table`.
-
-### `sql_table`
-
-The `sql_table` property is used as a concise way for defining a cube that uses
-a query like this: `SELECT * FROM table`. Instead of using the
-[`sql`](#parameters-sql) property, use `sql_table` with the table name that this
-cube will query.
-
-
-
-```javascript
-cube(`orders`, {
- sql_table: `public.orders`,
-});
-```
+ sql_table: orders
+ title: Product Orders
+ meta:
+ any: value
-```yaml
-cubes:
- - name: orders
- sql_table: public.orders
```
-### `sql_alias`
+### `pre_aggregations`
-Use `sql_alias` when auto-generated cube alias prefix is too long and truncated
-by DB such as Postgres:
+The `pre_aggregations` parameter is used to configure [pre-aggregations][ref-ref-pre-aggs].
-
+### `joins`
-```javascript
-cube(`order_facts`, {
- sql_table: `orders`,
- sql_alias: `ofacts`,
-});
-```
+The `joins` parameter is used to configure [joins][ref-ref-joins].
-```yaml
-cubes:
- - name: order_facts
- sql_table: orders
- sql_alias: ofacts
-```
+### `dimensions`
-
+The `dimensions` parameter is used to configure [dimensions][ref-ref-dimensions].
-It'll generate aliases for members such as `ofacts__count`. `sql_alias` affects
-all member names including pre-aggregation table names.
+### `hierarchies`
-### `title`
+The `hierarchies` parameter is used to configure [hierarchies][ref-ref-hierarchies].
-Use `title` to change the display name of the cube. By default, Cube will
-humanize the cube's name, so for instance, `users_orders` would become
-`Users Orders`. If default humanizing doesn't work in your case, please use the
-title parameter. It is highly recommended to give human readable names to your
-cubes. It will help everyone on a team better understand the data structure and
-will help maintain a consistent set of definitions across an organization.
+### `segments`
-
+The `segments` parameter is used to configure [segments][ref-ref-segments].
-```javascript
-cube(`orders`, {
- sql_table: `orders`,
- title: `Product Orders`,
-});
-```
+### `measures`
-```yaml
-cubes:
- - name: orders
- sql_table: orders
- title: Product Orders
-```
+The `measures` parameter is used to configure [measures][ref-ref-measures].
-
+### `access_policy`
+
+The `access_policy` parameter is used to configure [data access policies][ref-ref-dap].
[ref-config-driverfactory]: /reference/configuration/config#driverfactory
@@ -598,3 +626,4 @@ cubes:
[ref-ref-segments]: /reference/data-model/segments
[ref-ref-joins]: /reference/data-model/joins
[ref-ref-pre-aggs]: /reference/data-model/pre-aggregations
+[ref-ref-dap]: /reference/data-model/data-access-policies
\ No newline at end of file
diff --git a/docs/pages/reference/data-model/data-access-policies.mdx b/docs/pages/reference/data-model/data-access-policies.mdx
new file mode 100644
index 0000000000000..891189955adad
--- /dev/null
+++ b/docs/pages/reference/data-model/data-access-policies.mdx
@@ -0,0 +1,366 @@
+# Data access policies
+
+You can use the `access_policy` parameter within [cubes][ref-ref-cubes] and [views][ref-ref-views]
+to configure [data access policies][ref-dap] for them.
+
+## Parameters
+
+The `access_policy` parameter should define a list of access policies. Each policy
+can be configured using the following parameters:
+
+- [`role`](#role) defines which [data access role][ref-dap-roles] a policy applies
+to.
+- [`conditions`](#conditions) can be optionally used to specify when a policy
+takes effect.
+- [`member_level`](#member-level) and [`row_level`](#row-level) parameters are used
+to configure [member-level][ref-dap-mls] and [row-level][ref-dap-rls] access.
+
+### `role`
+
+The `role` parameter defines which [data access role][ref-dap-roles], as defined
+by the [`context_to_roles`][ref-context-to-roles] configuration parameter, a
+policy applies to. To define a policy that applies to all users regardless of
+their roles, use the _any role_ shorthand: `role: "*"`.
+
+In the following example, three access policies are defined, with the first one
+applying to all users and two other applying to users with `marketing` or
+`finance` roles, respectively.
+
+
+
+```yaml
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ # Applies to any role
+ - role: "*"
+ # ...
+
+ - role: marketing
+ # ...
+
+ - role: finance
+ # ...
+```
+
+```javascript
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ // Applies to any role
+ role: `*`,
+ // ...
+ },
+ {
+ role: `marketing`,
+ // ...
+ },
+ {
+ role: `finance`,
+ // ...
+ }
+ ]
+})
+```
+
+
+
+### `conditions`
+
+The optional `conditions` parameter, when present, defines a list of conditions
+that should all be `true` in order for a policy to take effect. Each condition is
+configured with an `if` parameter that is expected to reference the [security
+context][ref-sec-ctx].
+
+In the following example, a permissive policy for all roles will only apply to
+EMEA-based users, as determined by the `is_EMEA_based` attribute in the security
+context:
+
+
+
+```yaml
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - role: "*"
+ conditions:
+ - if: "{ securityContext.is_EMEA_based }"
+ member_level:
+ includes: "*"
+```
+
+```javascript
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ role: `*`,
+ conditions: [
+ { if: securityContext.is_EMEA_based }
+ ],
+ member_level: {
+ includes: `*`
+ }
+ }
+ ]
+})
+```
+
+
+
+You can use the `conditions` parameter to define multiple policies for the same
+role.
+
+In the following example, the first policy provides access to a _subset of members_
+to managers who are full-time employees while the other one provides access to
+_all members_ to managers who are full-time employees and have also completed a
+data privacy training:
+
+
+
+```yaml
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - role: manager
+ conditions:
+ - if: "{ securityContext.is_full_time_employee }"
+ member_level:
+ includes:
+ - status
+ - count
+
+ - role: manager
+ conditions:
+ - if: "{ securityContext.is_full_time_employee }"
+ - if: "{ securityContext.has_completed_privacy_training }"
+ member_level:
+ includes: "*"
+```
+
+```javascript
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ role: `manager`,
+ conditions: [
+ { if: securityContext.is_full_time_employee }
+ ],
+ member_level: {
+ includes: [
+ `status`,
+ `count`
+ ]
+ }
+ },
+ {
+ role: `manager`,
+ conditions: [
+ { if: securityContext.is_full_time_employee },
+ { if: securityContext.has_completed_privacy_training }
+ ],
+ member_level: {
+ includes: `*`
+ }
+ }
+ ]
+})
+```
+
+
+
+### `member_level`
+
+The optional `member_level` parameter, when present, configures [member-level
+access][ref-dap-mls] for a policy by specifying allowed or disallowed members.
+
+You can either provide a list of allowed members with the `includes` parameter,
+or a list of disallowed members with the `excludes` parameter. There's also the
+_all members_ shorthand for both of these paramaters: `includes: "*"`, `excludes: "*"`.
+
+In the following example, member-level access is configured this way:
+
+| Scope | Access |
+| --- | --- |
+| Users with the `manager` role | All members except for `count` |
+| Users with the `observer` role | All members except for `count` and `count_7d` |
+| Users with the `guest` role | Only the `count_30d` measure |
+| All other users | No access to this cube at all |
+
+
+
+```yaml
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - role: "*"
+ member_level:
+ # Includes nothing, i.e., excludes all members
+ includes: []
+
+ - role: manager
+ member_level:
+ # Includes all members except for `count`
+ excludes:
+ - count
+
+ - role: observer
+ member_level:
+ # Includes all members except for `count` and `count_7d`
+ excludes:
+ - count
+ - count_7d
+
+ - role: guest
+ # Includes only `count_30d`, excludes all other members
+ member_level:
+ includes:
+ - count_30d
+```
+
+```javascript
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ role: `*`,
+ // Includes nothing, i.e., excludes all members
+ member_level: {
+ includes: []
+ }
+ },
+ {
+ role: `manager`,
+ // Includes all members except for `count`
+ member_level: {
+ excludes: [
+ `count`
+ ]
+ }
+ },
+ {
+ role: `observer`,
+ // Includes all members except for `count` and `count_7d`
+ member_level: {
+ excludes: [
+ `count`,
+ `count_7d`
+ ]
+ }
+ },
+ {
+ role: `guest`,
+ // Includes only `count_30d`, excludes all other members
+ member_level: {
+ includes: [
+ `count_30d`
+ ]
+ }
+ }
+ ]
+})
+```
+
+
+
+Note that access policies also respect [member-level security][ref-mls] restrictions
+configured via `public` parameters. See [member-level access][ref-dap-mls] to
+learn more about policy evaluation.
+
+### `row_level`
+
+The optional `row_level` parameter, when present, configures [row-level
+access][ref-dap-rls] for a policy by specifying `filters` that should apply to result set rows.
+You can also use the optional `allow_all` parameter to explicitly allow or disallow all rows.
+
+In the following example, users with the `manager` role are allowed to access only
+rows that have the `state` dimension matching the state from the [security context][ref-sec-ctx].
+All other users are disallowed from accessing any rows at all.
+
+
+
+```yaml
+cubes:
+ - name: orders
+ # ...
+
+ access_policy:
+ - role: "*"
+ row_level:
+ allow_all: false
+
+ - role: manager
+ row_level:
+ filters:
+ - member: state
+ operator: eq
+ values: [ "{ securityContext.state }" ]
+```
+
+```javascript
+cube(`orders`, {
+ // ...
+
+ access_policy: [
+ {
+ role: `*`,
+ row_level: {
+ allow_all: false
+ }
+ },
+ {
+ role: `manager`,
+ row_level: {
+ filters: [
+ {
+ member: `state`,
+ operator: `equals`,
+ values: [ securityContext.state ]
+ }
+ ]
+ }
+ }
+ ]
+})
+```
+
+
+
+For convenience, row filters are configured using the same format as [filters in
+REST API][ref-rest-query-filters] queries, allowing to use the same set of
+[filter operators][ref-rest-query-ops], e.g., `equals`, `contains`, `gte`, etc.
+You can also use `and` and `or` parameters to combine multiple filters into
+[boolean logical operators][ref-rest-boolean-ops].
+
+Note that access policies also respect [row-level security][ref-rls] restrictions
+configured via the `query_rewrite` configuration option. See [row-level access][ref-dap-rls] to
+learn more about policy evaluation.
+
+
+[ref-ref-cubes]: /reference/data-model/cube
+[ref-ref-views]: /reference/data-model/view
+[ref-dap]: /product/auth/data-access-policies
+[ref-dap-roles]: /product/auth/data-access-policies#data-access-roles
+[ref-dap-mls]: /product/auth/data-access-policies#member-level-access
+[ref-dap-rls]: /product/auth/data-access-policies#row-level-access
+[ref-context-to-roles]: /reference/configuration/config#context_to_roles
+[ref-mls]: /product/auth/member-level-security
+[ref-rls]: /product/auth/row-level-security
+[ref-sec-ctx]: /product/auth/context
+[ref-rest-query-filters]: /product/apis-integrations/rest-api/query-format#filters-format
+[ref-rest-query-ops]: /product/apis-integrations/rest-api/query-format#filters-operators
+[ref-rest-boolean-ops]: /product/apis-integrations/rest-api/query-format#boolean-logical-operators
\ No newline at end of file
diff --git a/docs/pages/reference/data-model/dimensions.mdx b/docs/pages/reference/data-model/dimensions.mdx
index 7c35bb09898ac..cdeee806f31b4 100644
--- a/docs/pages/reference/data-model/dimensions.mdx
+++ b/docs/pages/reference/data-model/dimensions.mdx
@@ -6,11 +6,11 @@ redirect_from:
# Dimensions
-The `dimensions` property contains a set of dimensions. You can think about a
-dimension as an attribute related to a measure, e.g. the measure `user_count`
+You can use the `dimensions` parameter within [cubes][ref-ref-cubes] to define dimensions.
+You can think about a dimension as an attribute related to a measure, e.g. the measure `user_count`
can have dimensions like `country`, `age`, `occupation`, etc.
-Any dimension should have the following parameters: `name`, `sql` and `type`.
+Any dimension should have the following parameters: [`name`](#name), [`sql`](#sql), and [`type`](#type).
Dimensions can be also organized into [hierarchies][ref-ref-hierarchies].
@@ -699,6 +699,7 @@ cube(`orders`, {
+[ref-ref-cubes]: /reference/data-model/cube
[ref-schema-ref-joins]: /reference/data-model/joins
[ref-subquery]: /product/data-modeling/concepts/calculated-members#subquery-dimensions
[self-subquery]: #sub-query
diff --git a/docs/pages/reference/data-model/hierarchies.mdx b/docs/pages/reference/data-model/hierarchies.mdx
index 92212b49388bd..bcc4c382dcd39 100644
--- a/docs/pages/reference/data-model/hierarchies.mdx
+++ b/docs/pages/reference/data-model/hierarchies.mdx
@@ -1,7 +1,7 @@
# Hierarchies
-The `hierarchies` property contains a set of hierarchies. You can think about a
-hierarchy as a means to group [dimensions][ref-ref-dimensions] together and organize
+You can use the `hierarchies` parameter within [cubes][ref-ref-cubes] to define hierarchies.
+You can think about a hierarchy as a means to group [dimensions][ref-ref-dimensions] together and organize
them into levels of granularity, allowing users to drill down or roll up for analysis.
@@ -298,8 +298,9 @@ cubes:
+[ref-ref-cubes]: /reference/data-model/cube
[ref-ref-dimensions]: /reference/data-model/dimensions
[ref-naming]: /product/data-modeling/syntax#naming
-[ref-apis-support]: /product/apis-integrations#support-for-data-modeling
+[ref-apis-support]: /product/apis-integrations#data-modeling
[ref-playground]: /product/workspace/playground#viewing-the-data-model
[ref-viz-tools]: /product/configuration/visualization-tools
\ No newline at end of file
diff --git a/docs/pages/reference/data-model/joins.mdx b/docs/pages/reference/data-model/joins.mdx
index defb03fa38779..dab74c78ef6ed 100644
--- a/docs/pages/reference/data-model/joins.mdx
+++ b/docs/pages/reference/data-model/joins.mdx
@@ -6,9 +6,8 @@ redirect_from:
# Joins
-The `joins` parameter declares a block to define relationships between cubes. It
-allows users to access and compare fields from two or more cubes at the same
-time.
+You can use the `joins` parameter within [cubes][ref-ref-cubes] to define joins to other cubes.
+Joins allow to access and compare members from two or more cubes at the same time.
@@ -664,6 +663,8 @@ In case there are multiple join paths that can be used to join the same set of c
Cube makes join trees as predictable and stable as possible, but this isn't guaranteed in case multiple join paths exist.
Please use views to address join predictability and stability.
+
+[ref-ref-cubes]: /reference/data-model/cube
[ref-restapi-query-filter-op-set]:
/product/apis-integrations/rest-api/query-format#set
[ref-schema-fundamentals-join-dir]:
@@ -675,4 +676,4 @@ Please use views to address join predictability and stability.
[wiki-djikstra-alg]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm
[wiki-left-join]: https://en.wikipedia.org/wiki/Join_(SQL)#Left_outer_join
[wiki-1-1]: https://en.wikipedia.org/wiki/One-to-one_(data_model)
-[wiki-1-m]: https://en.wikipedia.org/wiki/One-to-many_(data_model)
+[wiki-1-m]: https://en.wikipedia.org/wiki/One-to-many_(data_model)
\ No newline at end of file
diff --git a/docs/pages/reference/data-model/measures.mdx b/docs/pages/reference/data-model/measures.mdx
index 64d378c23a02a..96ff9eb2ba724 100644
--- a/docs/pages/reference/data-model/measures.mdx
+++ b/docs/pages/reference/data-model/measures.mdx
@@ -6,10 +6,10 @@ redirect_from:
# Measures
-The `measures` parameter contains a set of measures and each measure is an
-aggregation over a certain column in your database table.
+You can use the `measures` parameter within [cubes][ref-ref-cubes] to define measures.
+Each measure is an aggregation over a certain column in your database table.
-Any measure should have the following parameters: `name`, `sql` and `type`.
+Any measure should have the following parameters: [`name`](#name), [`sql`](#sql), and [`type`](#type).
## Parameters
@@ -527,6 +527,7 @@ You can create calculated measures from several joined cubes. In this case, a
join will be created automatically.
+[ref-ref-cubes]: /reference/data-model/cube
[ref-schema-ref-types-formats-measures-types]:
/reference/data-model/types-and-formats#measure-types
[ref-schema-ref-types-formats-measures-formats]:
diff --git a/docs/pages/reference/data-model/pre-aggregations.mdx b/docs/pages/reference/data-model/pre-aggregations.mdx
index abea423da852e..3ff747b7a8d1e 100644
--- a/docs/pages/reference/data-model/pre-aggregations.mdx
+++ b/docs/pages/reference/data-model/pre-aggregations.mdx
@@ -6,8 +6,8 @@ redirect_from:
# Pre-aggregations
-[Pre-aggregations][ref-pre-aggs] can be defined using the `pre_aggregations`
-parameter of a [cube][ref-ref-cubes].
+You can use the `pre_aggregations` parameter within [cubes][ref-ref-cubes] to define
+[pre-aggregations][ref-pre-aggs].
Pre-aggregations must have, at minimum, a [name](#name) and a [type](#type).
Pre-aggregations must include all dimensions and measures you will query with.
diff --git a/docs/pages/reference/data-model/segments.mdx b/docs/pages/reference/data-model/segments.mdx
index 2c074f5aaddd5..e9a903a47f692 100644
--- a/docs/pages/reference/data-model/segments.mdx
+++ b/docs/pages/reference/data-model/segments.mdx
@@ -6,9 +6,10 @@ redirect_from:
# Segments
-Segments are predefined filters. You can use segments to define complex
-filtering logic in SQL. For example, users for one particular city can be
-treated as a segment:
+You can use the `segments` parameter within [cubes][ref-ref-cubes] to define segments.
+Segments are predefined filters. You can use segments to define complex filtering logic in SQL.
+
+For example, users for one particular city can be treated as a segment:
@@ -336,6 +337,7 @@ cubes:
+[ref-ref-cubes]: /reference/data-model/cube
[ref-backend-query]: /product/apis-integrations/rest-api/query-format
[ref-schema-gen]: /guides/recipes/code-reusability/schema-generation
[ref-naming]: /product/data-modeling/syntax#naming
diff --git a/docs/pages/reference/data-model/view.mdx b/docs/pages/reference/data-model/view.mdx
index 800bdb98b7eee..fe7bb50f74b45 100644
--- a/docs/pages/reference/data-model/view.mdx
+++ b/docs/pages/reference/data-model/view.mdx
@@ -152,7 +152,7 @@ above for `base_orders`.
The other required parameter inside the `cubes` block is `includes`. Use it
to list measures, dimensions, or segments you'd like to include into the view.
-To include all members from a cube, use the "includes all" form: `includes: "*"`.
+To include all members from a cube, use the _includes all_ shorthand: `includes: "*"`.
In that case, you can also use the `excludes` parameter to list members that
you'd like to exclude.
@@ -340,6 +340,10 @@ views:
+### `access_policy`
+
+The `access_policy` parameter is used to configure [data access policies][ref-ref-dap].
+
### `includes` (deprecated)
@@ -391,6 +395,7 @@ views:
[ref-naming]: /product/data-modeling/syntax#naming
[ref-apis]: /product/apis-integrations
[ref-ref-cubes]: /reference/data-model/cube
-[ref-apis-support]: /product/apis-integrations#support-for-data-modeling
+[ref-ref-dap]: /reference/data-model/data-access-policies
+[ref-apis-support]: /product/apis-integrations#data-modeling
[ref-playground]: /product/workspace/playground#viewing-the-data-model
[ref-viz-tools]: /product/configuration/visualization-tools
\ No newline at end of file
diff --git a/docs/redirects.json b/docs/redirects.json
index 62f19d77c508f..d17711d0eb1d8 100644
--- a/docs/redirects.json
+++ b/docs/redirects.json
@@ -1,4 +1,9 @@
[
+ {
+ "source": "/product/data-modeling/concepts/publicity",
+ "destination": "/product/auth/member-level-security",
+ "permanent": true
+ },
{
"source": "/guides/recipes/data-modeling/fiscal-year-quarter-dimensions",
"destination": "/guides/recipes/data-modeling/custom-granularity",