From a945a947ac7b7833fb97fa81478c550e126f2783 Mon Sep 17 00:00:00 2001
From: Alex Vanin <a.vanin@yadro.com>
Date: Mon, 16 Dec 2024 15:56:27 +0300
Subject: [PATCH] [#183] Unlink API.md to README file

This is useful for auto-generated document tools
which parse docs dir.

Signed-off-by: Alex Vanin <a.vanin@yadro.com>
---
 README.md              | 139 +----------------------------------------
 docs/api.md            |   4 +-
 docs/authentication.md | 108 ++++++++++++++++++++++++++++++++
 docs/nns.md            |  36 +++++++++++
 4 files changed, 148 insertions(+), 139 deletions(-)
 create mode 100644 docs/authentication.md
 create mode 100644 docs/nns.md

diff --git a/README.md b/README.md
index e1af0eb..adf793c 100644
--- a/README.md
+++ b/README.md
@@ -217,41 +217,8 @@ Also, in case of downloading, you need to have a file inside a container.
 ### NNS
 
 In all download/upload routes you can use container name instead of its id (`$CID`).
+Read more about it in [docs/nns.md](./docs/nns.md).
 
-Steps to start using name resolving:
-
-1. Enable NNS resolving in config (`rpc_endpoint` must be a valid neo rpc node, see [configs](./config) for other examples):
-
-```yaml
-rpc_endpoint: http://morph-chain.frostfs.devenv:30333
-resolve_order:
-  - nns
-```
-
-2. Make sure your container is registered in NNS contract. If you use [frostfs-dev-env](https://git.frostfs.info/TrueCloudLab/frostfs-dev-env)
-you can check if your container (e.g. with `container-name` name) is registered in NNS:
-
-```shell
-$ curl -s --data '{"id":1,"jsonrpc":"2.0","method":"getcontractstate","params":[1]}' \
-    http://morph-chain.frostfs.devenv:30333 | jq -r '.result.hash'
-
-0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667
-
-$ docker exec -it morph_chain neo-go \
-    contract testinvokefunction \
-    -r http://morph-chain.frostfs.devenv:30333 0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667 \
-    resolve string:container-name.container int:16 \
-    | jq -r '.stack[0].value | if type=="array" then .[0].value else . end' \
-    | base64 -d && echo
-
-7f3vvkw4iTiS5ZZbu5BQXEmJtETWbi3uUjLNaSs29xrL
-```
-
-3. Use container name instead of its `$CID`. For example:
-
-```shell
-$ curl http://localhost:8082/get_by_attribute/container-name/FileName/object-name
-```
 
 #### Create a container
 
@@ -462,109 +429,7 @@ object ID, like this:
 
 #### Authentication
 
-You can always upload files to public containers (open for anyone to put
-objects into), but for restricted containers you need to explicitly allow PUT
-operations for a request signed with your HTTP Gateway keys.
-
-If you don't want to manage gateway's secret keys and adjust policies when
-gateway configuration changes (new gate, key rotation, etc) or you plan to use
-public services, there is an option to let your application backend (or you) to
-issue Bearer Tokens and pass them from the client via gate down to FrostFS level
-to grant access.
-
-FrostFS Bearer Token basically is a container owner-signed policy (refer to FrostFS
-documentation for more details). There are two options to pass them to gateway:
- * "Authorization" header with "Bearer" type and base64-encoded token in
-   credentials field
- * "Bearer" cookie with base64-encoded token contents
-
-For example, you have a mobile application frontend with a backend part storing
-data in FrostFS. When a user authorizes in the mobile app, the backend issues a FrostFS
-Bearer token and provides it to the frontend. Then, the mobile app may generate
-some data and upload it via any available FrostFS HTTP Gateway by adding
-the corresponding header to the upload request. Accessing policy protected data
-works the same way.
-
-##### Example
-In order to generate a bearer token, you need to have wallet (which will be used to sign the token)
-
-1. Suppose you have a container with private policy for wallet key
-
-```
-$ frostfs-cli container create -r <endpoint> --wallet <wallet> -policy <policy> --basic-acl 0 --await
-CID: 9dfzyvq82JnFqp5svxcREf2iy6XNuifYcJPusEDnGK9Z
-
-$ frostfs-cli ape-manager add -r <endpoint> --wallet <wallet> \
-  --target-type container --target-name 9dfzyvq82JnFqp5svxcREf2iy6XNuifYcJPusEDnGK9Z \
-  --rule "allow Object.* RequestCondition:"\$Actor:publicKey"=03b09baabff3f6107c7e9acb8721a6fc5618d45b50247a314d82e548702cce8cd5 *" \
-  --chain-id <chainID>
-```
-
-
-2. Form a Bearer token (10000 is lifetime expiration in epoch) to impersonate
-   HTTP Gateway request as wallet signed request and save it to **bearer.json**:
-```
-{
-    "body": {
-        "allowImpersonate": true,
-        "lifetime": {
-            "exp": "10000",
-            "nbf": "0",
-            "iat": "0"
-        }
-    },
-    "signature": null
-}
-```
-
-3. Sign it with the wallet:
-```
-$ frostfs-cli util sign bearer-token --from bearer.json --to signed.json -w <wallet>
-```
-
-4. Encode to base64 to use in header:
-```
-$ base64 -w 0 signed.json
-# output: Ck4KKgoECAIQBhIiCiCZGdlbN7DPGPMg9rsWqV+p2XdMzUqknRiexewSFp8kmBIbChk17MUri6OJ0X5ftsHzy7NERDNFB4C92PcaGgMIkE4SZgohAxpsb7vfAso1F0X6hrm6WpRS14WsT3/Ct1SMoqRsT89KEkEEGxKi8GjKSf52YqhppgaOTQHbUsL3jn7SHLqS3ndAQ7NtAATnmRHleZw2V2xRRSRBQdjDC05KK83LhdSax72Fsw==
-```
-
-After that, the Bearer token can be used:
-
-```
-$ curl -F 'file=@cat.jpeg;filename=cat.jpeg' -H "Authorization: Bearer Ck4KKgoECAIQBhIiCiCZGdlbN7DPGPMg9rsWqV+p2XdMzUqknRiexewSFp8kmBIbChk17MUri6OJ0X5ftsHzy7NERDNFB4C92PcaGgMIkE4SZgohAxpsb7vfAso1F0X6hrm6WpRS14WsT3/Ct1SMoqRsT89KEkEEGxKi8GjKSf52YqhppgaOTQHbUsL3jn7SHLqS3ndAQ7NtAATnmRHleZw2V2xRRSRBQdjDC05KK83LhdSax72Fsw==" \
-  http://localhost:8082/upload/BJeErH9MWmf52VsR1mLWKkgF3pRm3FkubYxM7TZkBP4K
-# output:
-# {
-#	"object_id": "DhfES9nVrFksxGDD2jQLunGADfrXExxNwqXbDafyBn9X",
-#	"container_id": "BJeErH9MWmf52VsR1mLWKkgF3pRm3FkubYxM7TZkBP4K"
-# }
-```
-
-##### Note: Bearer Token owner
-
-You can specify exact key who can use Bearer Token (gateway wallet address).
-To do this, encode wallet address in base64 format
-
-```
-$ echo 'NhVtreTTCoqsMQV5Wp55fqnriiUCpEaKm3' | base58 --decode | base64
-# output: NezFK4ujidF+X7bB88uzREQzRQeAvdj3Gg==
-```
-
-Then specify this value in Bearer Token Json
-```
-{
-    "body": {
-        "ownerID": {
-            "value": "NezFK4ujidF+X7bB88uzREQzRQeAvdj3Gg=="
-        },
-        ...
-```
-
-##### Note: Policy override
-
-Instead of impersonation, you can define the set of policies that will be applied
-to the request sender. This allows to restrict access to specific operation and
-specific objects without giving full impersonation control to the token user.
+Read more about request authentication in [docs/authentication.md](./docs/authemtnication.md)
 
 ### Metrics and Pprof
 
diff --git a/docs/api.md b/docs/api.md
index f7eb3a4..e59956a 100644
--- a/docs/api.md
+++ b/docs/api.md
@@ -8,7 +8,7 @@
 | `/zip/{cid}/{prefix}`                           | [Download objects in archive](#download-zip) |
 
 **Note:** `cid` parameter can be base58 encoded container ID or container name
-(the name must be registered in NNS, see appropriate section in [README](../README.md#nns)).
+(the name must be registered in NNS, see appropriate section in [nns.md](./nns.md)).
 
 Route parameters can be:
 
@@ -18,7 +18,7 @@ Route parameters can be:
 
 ### Bearer token
 
-All routes can accept [bearer token](../README.md#authentication) from:
+All routes can accept [bearer token](./authentication.md) from:
 
 * `Authorization` header with `Bearer` type and base64-encoded token in
   credentials field
diff --git a/docs/authentication.md b/docs/authentication.md
new file mode 100644
index 0000000..d8bb235
--- /dev/null
+++ b/docs/authentication.md
@@ -0,0 +1,108 @@
+# Request authentication
+
+HTTP Gateway does not authorize requests. Gateway converts HTTP request to a 
+FrostFS request and signs it with its own private key. 
+
+You can always upload files to public containers (open for anyone to put
+objects into), but for restricted containers you need to explicitly allow PUT
+operations for a request signed with your HTTP Gateway keys.
+
+If you don't want to manage gateway's secret keys and adjust policies when
+gateway configuration changes (new gate, key rotation, etc) or you plan to use
+public services, there is an option to let your application backend (or you) to
+issue Bearer Tokens and pass them from the client via gate down to FrostFS level
+to grant access.
+
+FrostFS Bearer Token basically is a container owner-signed policy (refer to FrostFS
+documentation for more details). There are two options to pass them to gateway:
+* "Authorization" header with "Bearer" type and base64-encoded token in
+  credentials field
+* "Bearer" cookie with base64-encoded token contents
+
+For example, you have a mobile application frontend with a backend part storing
+data in FrostFS. When a user authorizes in the mobile app, the backend issues a FrostFS
+Bearer token and provides it to the frontend. Then, the mobile app may generate
+some data and upload it via any available FrostFS HTTP Gateway by adding
+the corresponding header to the upload request. Accessing policy protected data
+works the same way.
+
+##### Example
+In order to generate a bearer token, you need to have wallet (which will be used to sign the token)
+
+1. Suppose you have a container with private policy for wallet key
+
+```
+$ frostfs-cli container create -r <endpoint> --wallet <wallet> -policy <policy> --basic-acl 0 --await
+CID: 9dfzyvq82JnFqp5svxcREf2iy6XNuifYcJPusEDnGK9Z
+
+$ frostfs-cli ape-manager add -r <endpoint> --wallet <wallet> \
+  --target-type container --target-name 9dfzyvq82JnFqp5svxcREf2iy6XNuifYcJPusEDnGK9Z \
+  --rule "allow Object.* RequestCondition:"\$Actor:publicKey"=03b09baabff3f6107c7e9acb8721a6fc5618d45b50247a314d82e548702cce8cd5 *" \
+  --chain-id <chainID>
+```
+
+
+2. Form a Bearer token (10000 is lifetime expiration in epoch) to impersonate
+   HTTP Gateway request as wallet signed request and save it to **bearer.json**:
+```
+{
+    "body": {
+        "allowImpersonate": true,
+        "lifetime": {
+            "exp": "10000",
+            "nbf": "0",
+            "iat": "0"
+        }
+    },
+    "signature": null
+}
+```
+
+3. Sign it with the wallet:
+```
+$ frostfs-cli util sign bearer-token --from bearer.json --to signed.json -w <wallet>
+```
+
+4. Encode to base64 to use in header:
+```
+$ base64 -w 0 signed.json
+# output: Ck4KKgoECAIQBhIiCiCZGdlbN7DPGPMg9rsWqV+p2XdMzUqknRiexewSFp8kmBIbChk17MUri6OJ0X5ftsHzy7NERDNFB4C92PcaGgMIkE4SZgohAxpsb7vfAso1F0X6hrm6WpRS14WsT3/Ct1SMoqRsT89KEkEEGxKi8GjKSf52YqhppgaOTQHbUsL3jn7SHLqS3ndAQ7NtAATnmRHleZw2V2xRRSRBQdjDC05KK83LhdSax72Fsw==
+```
+
+After that, the Bearer token can be used:
+
+```
+$ curl -F 'file=@cat.jpeg;filename=cat.jpeg' -H "Authorization: Bearer Ck4KKgoECAIQBhIiCiCZGdlbN7DPGPMg9rsWqV+p2XdMzUqknRiexewSFp8kmBIbChk17MUri6OJ0X5ftsHzy7NERDNFB4C92PcaGgMIkE4SZgohAxpsb7vfAso1F0X6hrm6WpRS14WsT3/Ct1SMoqRsT89KEkEEGxKi8GjKSf52YqhppgaOTQHbUsL3jn7SHLqS3ndAQ7NtAATnmRHleZw2V2xRRSRBQdjDC05KK83LhdSax72Fsw==" \
+  http://localhost:8082/upload/BJeErH9MWmf52VsR1mLWKkgF3pRm3FkubYxM7TZkBP4K
+# output:
+# {
+#	"object_id": "DhfES9nVrFksxGDD2jQLunGADfrXExxNwqXbDafyBn9X",
+#	"container_id": "BJeErH9MWmf52VsR1mLWKkgF3pRm3FkubYxM7TZkBP4K"
+# }
+```
+
+##### Note: Bearer Token owner
+
+You can specify exact key who can use Bearer Token (gateway wallet address).
+To do this, encode wallet address in base64 format
+
+```
+$ echo 'NhVtreTTCoqsMQV5Wp55fqnriiUCpEaKm3' | base58 --decode | base64
+# output: NezFK4ujidF+X7bB88uzREQzRQeAvdj3Gg==
+```
+
+Then specify this value in Bearer Token Json
+```
+{
+    "body": {
+        "ownerID": {
+            "value": "NezFK4ujidF+X7bB88uzREQzRQeAvdj3Gg=="
+        },
+        ...
+```
+
+##### Note: Policy override
+
+Instead of impersonation, you can define the set of policies that will be applied
+to the request sender. This allows to restrict access to specific operation and
+specific objects without giving full impersonation control to the token user.
diff --git a/docs/nns.md b/docs/nns.md
new file mode 100644
index 0000000..acb9f21
--- /dev/null
+++ b/docs/nns.md
@@ -0,0 +1,36 @@
+# Nicename Resolving with NNS
+
+Steps to start using name resolving:
+
+1. Enable NNS resolving in config (`rpc_endpoint` must be a valid neo rpc node, see [configs](./config) for other examples):
+
+```yaml
+rpc_endpoint: http://morph-chain.frostfs.devenv:30333
+resolve_order:
+  - nns
+```
+
+2. Make sure your container is registered in NNS contract. If you use [frostfs-dev-env](https://git.frostfs.info/TrueCloudLab/frostfs-dev-env)
+   you can check if your container (e.g. with `container-name` name) is registered in NNS:
+
+```shell
+$ curl -s --data '{"id":1,"jsonrpc":"2.0","method":"getcontractstate","params":[1]}' \
+    http://morph-chain.frostfs.devenv:30333 | jq -r '.result.hash'
+
+0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667
+
+$ docker exec -it morph_chain neo-go \
+    contract testinvokefunction \
+    -r http://morph-chain.frostfs.devenv:30333 0x8e6c3cd4b976b28e84a3788f6ea9e2676c15d667 \
+    resolve string:container-name.container int:16 \
+    | jq -r '.stack[0].value | if type=="array" then .[0].value else . end' \
+    | base64 -d && echo
+
+7f3vvkw4iTiS5ZZbu5BQXEmJtETWbi3uUjLNaSs29xrL
+```
+
+3. Use container name instead of its `$CID`. For example:
+
+```shell
+$ curl http://localhost:8082/get_by_attribute/container-name/FileName/object-name
+```