From 5cafdabd5f03960c0c69c3e4ccfd5f34fd2aee19 Mon Sep 17 00:00:00 2001 From: D050513 Date: Thu, 31 Aug 2023 10:56:45 +0200 Subject: [PATCH 1/6] improve cds.auth --- node.js/authentication.md | 22 +++++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/node.js/authentication.md b/node.js/authentication.md index 3aaf2d341..d8dcbde54 100644 --- a/node.js/authentication.md +++ b/node.js/authentication.md @@ -97,6 +97,19 @@ this.before('*', function (req) { }) ``` +Alternatively, you can also use the sealed instance `cds.User.privileged` directly, i.e., `const user = cds.User.privileged`. + +### cds.**User.Anonymous** class { #anonymous-user } + +Class `cds.User.Anonymous` allows you to instantiate an anonymous user (`const user = new cds.User.Anonymous`), for example in a [custom authentication](#custom) implementation. + +Alternatively, you can also use the sealed instance `cds.User.anonymous` directly, i.e., `const user = cds.User.anonymous`. + +### cds.**User.default** { #default-user } + +If a request couldn't be authenticated, for example due to a missing authorization header, the built-in authentication strategies assign the default user to the request, i.e., `req.user = new cds.User.default`, ensuring that `req.user` is always set. + +By default, `cds.User.default` points to `cds.User.Anonymous`. However, you can override this, for example to be `cds.User.Privileged` in tests, or to be any other class that returns an instance of `cds.User`. ### Authorization Enforcement {.h2 #enforcement } @@ -366,8 +379,7 @@ npm add @sap/xssec ::: -### Custom Authentication {#custom } - +### Custom Authentication { #custom } You can configure an own implementation by specifying an own `impl` as follows: @@ -379,7 +391,7 @@ You can configure an own implementation by specifying an own `impl` as follows: } ``` -Essentially, custom authentication middlewares must do two things. First, they must [fulfill the `req.user` contract](#cds-user) by assigning an instance of `cds.User` or a look-alike to the incoming request at `req.user`. Second, if running in a multitenant environment, `req.tenant` must be set to a string identifying the tenant that is addressed by the incoming request. +Essentially, custom authentication middlewares must do two things. First, they _must_ [fulfill the `req.user` contract](#cds-user) by assigning an instance of `cds.User` or a look-alike to the incoming request at `req.user`. Use [cds.User.anonymous](#anonymous-user) as the fallback option. Second, if running in a multitenant environment, `req.tenant` must be set to a string identifying the tenant that is addressed by the incoming request. ```js @@ -399,6 +411,10 @@ module.exports = function custom_auth (req, res, next) { [If you want to customize the user ID, please also have a look at this example.](./middlewares#customization-of-req-user){.learn-more} +## Authentication Enforced in Production + +In a productive scenario with an authentication strategy configured, for example the default `xsuaa`, all CAP service endpoints are authenticated by default, regardless of the authorization model. That is, all services without `@restrict` or `@requires` implicitely get `@requires: 'authenticated-user'`. This can be disabled via feature flag `cds.env.requires.auth.restrict_all_services: false`, or by using [mocked authentication](#mocked) explicitly in production. + ## XSUAA in Hybrid Setup {#xsuaa-setup} ### Prepare Local Environment From aad5ca523752f6e056dab34169cce2c091390201 Mon Sep 17 00:00:00 2001 From: sjvans <30337871+sjvans@users.noreply.github.com> Date: Thu, 31 Aug 2023 12:43:31 +0200 Subject: [PATCH 2/6] Update node.js/authentication.md --- node.js/authentication.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/node.js/authentication.md b/node.js/authentication.md index d8dcbde54..d05fb29c6 100644 --- a/node.js/authentication.md +++ b/node.js/authentication.md @@ -413,7 +413,9 @@ module.exports = function custom_auth (req, res, next) { ## Authentication Enforced in Production -In a productive scenario with an authentication strategy configured, for example the default `xsuaa`, all CAP service endpoints are authenticated by default, regardless of the authorization model. That is, all services without `@restrict` or `@requires` implicitely get `@requires: 'authenticated-user'`. This can be disabled via feature flag `cds.env.requires.auth.restrict_all_services: false`, or by using [mocked authentication](#mocked) explicitly in production. +In a productive scenario with an authentication strategy configured, for example the default `xsuaa`, all CAP service endpoints are authenticated by default, regardless of the authorization model. That is, all services without `@restrict` or `@requires` implicitely get `@requires: 'authenticated-user'`. + +This can be disabled via feature flag `cds.env.requires.auth.restrict_all_services: false`, or by using [mocked authentication](#mocked) explicitly in production. ## XSUAA in Hybrid Setup {#xsuaa-setup} From cffab5ba8bcaab6422975423caebd93180568880 Mon Sep 17 00:00:00 2001 From: sjvans <30337871+sjvans@users.noreply.github.com> Date: Thu, 31 Aug 2023 12:56:09 +0200 Subject: [PATCH 3/6] Update node.js/authentication.md --- node.js/authentication.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/node.js/authentication.md b/node.js/authentication.md index d05fb29c6..4c694c278 100644 --- a/node.js/authentication.md +++ b/node.js/authentication.md @@ -391,7 +391,11 @@ You can configure an own implementation by specifying an own `impl` as follows: } ``` -Essentially, custom authentication middlewares must do two things. First, they _must_ [fulfill the `req.user` contract](#cds-user) by assigning an instance of `cds.User` or a look-alike to the incoming request at `req.user`. Use [cds.User.anonymous](#anonymous-user) as the fallback option. Second, if running in a multitenant environment, `req.tenant` must be set to a string identifying the tenant that is addressed by the incoming request. +Essentially, custom authentication middlewares must do two things: + +First, they _must_ [fulfill the `req.user` contract](#cds-user) by assigning an instance of `cds.User` or a look-alike to the incoming request at `req.user`. Use [new cds.User.default](#default-user) as the fallback option. + +Second, if running in a multitenant environment, `req.tenant` must be set to a string identifying the tenant that is addressed by the incoming request. ```js From 99953e1dedf97f1632e61ca60925b45de9e7a6e1 Mon Sep 17 00:00:00 2001 From: sjvans <30337871+sjvans@users.noreply.github.com> Date: Thu, 31 Aug 2023 14:24:01 +0200 Subject: [PATCH 4/6] jwt is default in production --- node.js/authentication.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/node.js/authentication.md b/node.js/authentication.md index 4c694c278..53c370190 100644 --- a/node.js/authentication.md +++ b/node.js/authentication.md @@ -69,14 +69,11 @@ User-related attributes, for example, from JWT tokens These correspond to `$user.` in [`@restrict` annotations](../guides/authorization) of your CDS models {.indent} - - ### DEPRECATED: user.tenant : string {#user-tenant} [Use `req/msg.tenant` instead.](events#tenant){.learn-more} - ### DEPRECATED: user.locale : string {#user-locale} [Use `req/msg.locale` instead.](events#locale){.learn-more} @@ -99,18 +96,21 @@ this.before('*', function (req) { Alternatively, you can also use the sealed instance `cds.User.privileged` directly, i.e., `const user = cds.User.privileged`. + ### cds.**User.Anonymous** class { #anonymous-user } Class `cds.User.Anonymous` allows you to instantiate an anonymous user (`const user = new cds.User.Anonymous`), for example in a [custom authentication](#custom) implementation. Alternatively, you can also use the sealed instance `cds.User.anonymous` directly, i.e., `const user = cds.User.anonymous`. + ### cds.**User.default** { #default-user } If a request couldn't be authenticated, for example due to a missing authorization header, the built-in authentication strategies assign the default user to the request, i.e., `req.user = new cds.User.default`, ensuring that `req.user` is always set. By default, `cds.User.default` points to `cds.User.Anonymous`. However, you can override this, for example to be `cds.User.Privileged` in tests, or to be any other class that returns an instance of `cds.User`. + ### Authorization Enforcement {.h2 #enforcement } Applications can use the `req.user` APIs to do programmatic enforcement. @@ -144,16 +144,17 @@ cds.serve ('CustomerService') .with (function(){ }) ``` + ## Authentication Strategies {#strategies} -CAP ships with a few prebuilt authentication strategies, used by default: [`mocked`](#mocked) during development and [`xsuaa`](#xsuaa) in production. +CAP ships with a few prebuilt authentication strategies, used by default: [`mocked`](#mocked) during development and [`jwt`](#jwt) in production. You can override these defaults and configure the authentication strategy to be used through the `cds.requires.auth` [config option in `cds.env`](./cds-env), for example: ::: code-group ```json [package.json] "cds": { "requires": { - "auth": "xsuaa" + "auth": "jwt" } } ``` @@ -180,6 +181,7 @@ This strategy creates a user that passes all authorization checks. It’s meant ``` ::: + ### Mocked Authentication {.h2 #mocked } This authentication strategy uses basic authentication with pre-defined mock users during development. @@ -219,6 +221,7 @@ You can optionally configure users as follows: ``` ::: + #### Pre-defined Mock Users {#mock-users} The default configuration shipped with `@sap/cds` specifies these users: @@ -325,7 +328,6 @@ npm add @sap/xssec Authentication kind `xsuaa` is a logical extension of kind [`jwt`](#jwt) that additionally offers access to SAML attributes through `req.user.attr` (for example, `req.user.attr.familyName`). - **Prerequisites:** You need to add [@sap/xssec](https://help.sap.com/docs/HANA_CLOUD_DATABASE/b9902c314aef4afb8f7a29bf8c5b37b3/54513272339246049bf438a03a8095e4.html#loio54513272339246049bf438a03a8095e4__section_atx_2vt_vt) to your project: ```sh npm add @sap/xssec @@ -397,7 +399,6 @@ First, they _must_ [fulfill the `req.user` contract](#cds-user) by assigning an Second, if running in a multitenant environment, `req.tenant` must be set to a string identifying the tenant that is addressed by the incoming request. - ```js module.exports = function custom_auth (req, res, next) { // do your custom authentication @@ -415,12 +416,14 @@ module.exports = function custom_auth (req, res, next) { [If you want to customize the user ID, please also have a look at this example.](./middlewares#customization-of-req-user){.learn-more} + ## Authentication Enforced in Production -In a productive scenario with an authentication strategy configured, for example the default `xsuaa`, all CAP service endpoints are authenticated by default, regardless of the authorization model. That is, all services without `@restrict` or `@requires` implicitely get `@requires: 'authenticated-user'`. +In a productive scenario with an authentication strategy configured, for example the default `jwt`, all CAP service endpoints are authenticated by default, regardless of the authorization model. That is, all services without `@restrict` or `@requires` implicitely get `@requires: 'authenticated-user'`. This can be disabled via feature flag `cds.env.requires.auth.restrict_all_services: false`, or by using [mocked authentication](#mocked) explicitly in production. + ## XSUAA in Hybrid Setup {#xsuaa-setup} ### Prepare Local Environment From 88aab77d6265e49375412690443740ef22900ae5 Mon Sep 17 00:00:00 2001 From: sjvans <30337871+sjvans@users.noreply.github.com> Date: Fri, 1 Sep 2023 12:35:37 +0200 Subject: [PATCH 5/6] sealed -> ready-to-use --- node.js/authentication.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node.js/authentication.md b/node.js/authentication.md index 53c370190..6e93be8e1 100644 --- a/node.js/authentication.md +++ b/node.js/authentication.md @@ -94,14 +94,14 @@ this.before('*', function (req) { }) ``` -Alternatively, you can also use the sealed instance `cds.User.privileged` directly, i.e., `const user = cds.User.privileged`. +Alternatively, you can also use the ready-to-use instance `cds.User.privileged` directly, i.e., `const user = cds.User.privileged`. ### cds.**User.Anonymous** class { #anonymous-user } Class `cds.User.Anonymous` allows you to instantiate an anonymous user (`const user = new cds.User.Anonymous`), for example in a [custom authentication](#custom) implementation. -Alternatively, you can also use the sealed instance `cds.User.anonymous` directly, i.e., `const user = cds.User.anonymous`. +Alternatively, you can also use the ready-to-use instance `cds.User.anonymous` directly, i.e., `const user = cds.User.anonymous`. ### cds.**User.default** { #default-user } From f9a3dd47b75d0bdd5905073f9ca5f4a73e16814c Mon Sep 17 00:00:00 2001 From: sjvans <30337871+sjvans@users.noreply.github.com> Date: Fri, 1 Sep 2023 13:02:44 +0200 Subject: [PATCH 6/6] Apply suggestions from code review Co-authored-by: Daniel Hutzel --- node.js/authentication.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/node.js/authentication.md b/node.js/authentication.md index 6e93be8e1..2500ae8e0 100644 --- a/node.js/authentication.md +++ b/node.js/authentication.md @@ -106,7 +106,7 @@ Alternatively, you can also use the ready-to-use instance `cds.User.anonymous` d ### cds.**User.default** { #default-user } -If a request couldn't be authenticated, for example due to a missing authorization header, the built-in authentication strategies assign the default user to the request, i.e., `req.user = new cds.User.default`, ensuring that `req.user` is always set. +If a request couldn't be authenticated, for example due to a missing authorization header, the framework will use `cds.User.default` as fallback. By default, `cds.User.default` points to `cds.User.Anonymous`. However, you can override this, for example to be `cds.User.Privileged` in tests, or to be any other class that returns an instance of `cds.User`. @@ -395,7 +395,7 @@ You can configure an own implementation by specifying an own `impl` as follows: Essentially, custom authentication middlewares must do two things: -First, they _must_ [fulfill the `req.user` contract](#cds-user) by assigning an instance of `cds.User` or a look-alike to the incoming request at `req.user`. Use [new cds.User.default](#default-user) as the fallback option. +First, they _must_ [fulfill the `req.user` contract](#cds-user) by assigning an instance of `cds.User` or a look-alike to the incoming request at `req.user`. Second, if running in a multitenant environment, `req.tenant` must be set to a string identifying the tenant that is addressed by the incoming request.