diff --git a/api/swagger.yml b/api/swagger.yml index 7d7a62a9a6f..3a35f4cd9b2 100644 --- a/api/swagger.yml +++ b/api/swagger.yml @@ -3217,6 +3217,103 @@ paths: default: $ref: "#/components/responses/ServerError" + /auth/get-token/start: + get: + tags: + - auth + - experimental + security: [] # This a way to log in, no auth available. + operationId: getTokenRedirect + summary: start acquiring a token by logging in on a browser + responses: + 303: + description: login on this page, await results on the mailbox URL + headers: + Location: + schema: + type: string + description: open this URL on the browser + X-LakeFS-Mailbox: + schema: + type: string + description: GET the token from this mailbox. Keep the mailbox SECRET! + 401: + $ref: "#/components/responses/Unauthorized" + 429: + description: too many requests + 501: + description: Not implemented in this edition. + $ref: "#/components/responses/NotImplemented" + default: + $ref: "#/components/responses/ServerError" + + /auth/get-token/mailboxes/{mailbox}: + parameters: + - in: path + name: mailbox + required: true + schema: + type: string + description: mailbox returned by getTokenRedirect + get: + tags: + - auth + - experimental + security: [] # This a way to log in, no auth available. + operationId: getTokenFromMailbox + summary: receive the token after user has authenticated on redirect URL. + responses: + 200: + description: user successfully logged in + content: + application/json: + schema: + $ref: "#/components/schemas/AuthenticationToken" + 401: + description: bad mailbox or user has not logged in yet + $ref: "#/components/responses/Unauthorized" + 404: + description: not found or user has not logged in yet + $ref: "#/components/responses/NotFound" + 429: + description: too many requests + 501: + description: not implemented in this edition. + $ref: "#/components/responses/NotImplemented" + default: + $ref: "#/components/responses/ServerError" + + /auth/get-token/release-token/{loginRequestToken}: + parameters: + - in: path + # The mailbox is secret. It is identified by the loginRequestToken - a JWT which is + # _not_ secret. So this JWT can safely go in a header. + name: loginRequestToken + required: true + schema: + type: string + maxLength: 1024 + description: login request token returned by getTokenRedirect. + get: # Called by opening a URL on the browser! + tags: + - auth + - experimental + operationId: releaseTokenToMailbox + summary: release a token for the current (authenticated) user to the mailbox of this login request. + responses: + 204: + description: token released + 401: + description: bad token or user has not logged in yet + $ref: "#/components/responses/Unauthorized" + 429: + description: too many requests + 501: + description: not implemented in this edition. + $ref: "#/components/responses/NotImplemented" + default: + $ref: "#/components/responses/ServerError" + /repositories: get: tags: diff --git a/clients/java/README.md b/clients/java/README.md index 208984be2c1..ce4572f595b 100644 --- a/clients/java/README.md +++ b/clients/java/README.md @@ -170,6 +170,8 @@ Class | Method | HTTP request | Description *AuthApi* | [**getGroup**](docs/AuthApi.md#getGroup) | **GET** /auth/groups/{groupId} | get group *AuthApi* | [**getGroupACL**](docs/AuthApi.md#getGroupACL) | **GET** /auth/groups/{groupId}/acl | get ACL of group *AuthApi* | [**getPolicy**](docs/AuthApi.md#getPolicy) | **GET** /auth/policies/{policyId} | get policy +*AuthApi* | [**getTokenFromMailbox**](docs/AuthApi.md#getTokenFromMailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +*AuthApi* | [**getTokenRedirect**](docs/AuthApi.md#getTokenRedirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser *AuthApi* | [**getUser**](docs/AuthApi.md#getUser) | **GET** /auth/users/{userId} | get user *AuthApi* | [**listGroupMembers**](docs/AuthApi.md#listGroupMembers) | **GET** /auth/groups/{groupId}/members | list group members *AuthApi* | [**listGroupPolicies**](docs/AuthApi.md#listGroupPolicies) | **GET** /auth/groups/{groupId}/policies | list group policies @@ -182,6 +184,7 @@ Class | Method | HTTP request | Description *AuthApi* | [**listUsers**](docs/AuthApi.md#listUsers) | **GET** /auth/users | list users *AuthApi* | [**login**](docs/AuthApi.md#login) | **POST** /auth/login | perform a login *AuthApi* | [**oauthCallback**](docs/AuthApi.md#oauthCallback) | **GET** /oidc/callback | +*AuthApi* | [**releaseTokenToMailbox**](docs/AuthApi.md#releaseTokenToMailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. *AuthApi* | [**setGroupACL**](docs/AuthApi.md#setGroupACL) | **POST** /auth/groups/{groupId}/acl | set ACL of group *AuthApi* | [**updatePolicy**](docs/AuthApi.md#updatePolicy) | **PUT** /auth/policies/{policyId} | update policy *BranchesApi* | [**cherryPick**](docs/BranchesApi.md#cherryPick) | **POST** /repositories/{repository}/branches/{branch}/cherry-pick | Replay the changes from the given commit on the branch @@ -205,10 +208,13 @@ Class | Method | HTTP request | Description *ExperimentalApi* | [**getExternalPrincipal**](docs/ExperimentalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id *ExperimentalApi* | [**getLicense**](docs/ExperimentalApi.md#getLicense) | **GET** /license | *ExperimentalApi* | [**getPullRequest**](docs/ExperimentalApi.md#getPullRequest) | **GET** /repositories/{repository}/pulls/{pull_request} | get pull request +*ExperimentalApi* | [**getTokenFromMailbox**](docs/ExperimentalApi.md#getTokenFromMailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +*ExperimentalApi* | [**getTokenRedirect**](docs/ExperimentalApi.md#getTokenRedirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser *ExperimentalApi* | [**hardResetBranch**](docs/ExperimentalApi.md#hardResetBranch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch *ExperimentalApi* | [**listPullRequests**](docs/ExperimentalApi.md#listPullRequests) | **GET** /repositories/{repository}/pulls | list pull requests *ExperimentalApi* | [**listUserExternalPrincipals**](docs/ExperimentalApi.md#listUserExternalPrincipals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user *ExperimentalApi* | [**mergePullRequest**](docs/ExperimentalApi.md#mergePullRequest) | **PUT** /repositories/{repository}/pulls/{pull_request}/merge | merge pull request +*ExperimentalApi* | [**releaseTokenToMailbox**](docs/ExperimentalApi.md#releaseTokenToMailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. *ExperimentalApi* | [**stsLogin**](docs/ExperimentalApi.md#stsLogin) | **POST** /sts/login | perform a login with STS *ExperimentalApi* | [**updateObjectUserMetadata**](docs/ExperimentalApi.md#updateObjectUserMetadata) | **PUT** /repositories/{repository}/branches/{branch}/objects/stat/user_metadata | rewrite (all) object metadata *ExperimentalApi* | [**updatePullRequest**](docs/ExperimentalApi.md#updatePullRequest) | **PATCH** /repositories/{repository}/pulls/{pull_request} | update pull request diff --git a/clients/java/api/openapi.yaml b/clients/java/api/openapi.yaml index b2a0434f298..89dc9c6a9ed 100644 --- a/clients/java/api/openapi.yaml +++ b/clients/java/api/openapi.yaml @@ -1952,6 +1952,144 @@ paths: - auth x-content-type: application/json x-accepts: application/json + /auth/get-token/start: + get: + operationId: getTokenRedirect + responses: + "303": + description: "login on this page, await results on the mailbox URL" + headers: + Location: + description: open this URL on the browser + explode: false + schema: + type: string + style: simple + X-LakeFS-Mailbox: + description: GET the token from this mailbox. Keep the mailbox SECRET! + explode: false + schema: + type: string + style: simple + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + "429": + description: too many requests + "501": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Not Implemented + default: + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Internal Server Error + security: [] + summary: start acquiring a token by logging in on a browser + tags: + - auth + - experimental + x-accepts: application/json + /auth/get-token/mailboxes/{mailbox}: + get: + operationId: getTokenFromMailbox + parameters: + - description: mailbox returned by getTokenRedirect + explode: false + in: path + name: mailbox + required: true + schema: + type: string + style: simple + responses: + "200": + content: + application/json: + schema: + $ref: '#/components/schemas/AuthenticationToken' + description: user successfully logged in + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + "404": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Resource Not Found + "429": + description: too many requests + "501": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Not Implemented + default: + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Internal Server Error + security: [] + summary: receive the token after user has authenticated on redirect URL. + tags: + - auth + - experimental + x-accepts: application/json + /auth/get-token/release-token/{loginRequestToken}: + get: + operationId: releaseTokenToMailbox + parameters: + - description: login request token returned by getTokenRedirect. + explode: false + in: path + name: loginRequestToken + required: true + schema: + maxLength: 1024 + type: string + style: simple + responses: + "204": + description: token released + "401": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Unauthorized + "429": + description: too many requests + "501": + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Not Implemented + default: + content: + application/json: + schema: + $ref: '#/components/schemas/Error' + description: Internal Server Error + summary: release a token for the current (authenticated) user to the mailbox + of this login request. + tags: + - auth + - experimental + x-accepts: application/json /repositories: get: operationId: listRepositories diff --git a/clients/java/docs/AuthApi.md b/clients/java/docs/AuthApi.md index fa4d266979e..984f299c360 100644 --- a/clients/java/docs/AuthApi.md +++ b/clients/java/docs/AuthApi.md @@ -27,6 +27,8 @@ All URIs are relative to */api/v1* | [**getGroup**](AuthApi.md#getGroup) | **GET** /auth/groups/{groupId} | get group | | [**getGroupACL**](AuthApi.md#getGroupACL) | **GET** /auth/groups/{groupId}/acl | get ACL of group | | [**getPolicy**](AuthApi.md#getPolicy) | **GET** /auth/policies/{policyId} | get policy | +| [**getTokenFromMailbox**](AuthApi.md#getTokenFromMailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. | +| [**getTokenRedirect**](AuthApi.md#getTokenRedirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser | | [**getUser**](AuthApi.md#getUser) | **GET** /auth/users/{userId} | get user | | [**listGroupMembers**](AuthApi.md#listGroupMembers) | **GET** /auth/groups/{groupId}/members | list group members | | [**listGroupPolicies**](AuthApi.md#listGroupPolicies) | **GET** /auth/groups/{groupId}/policies | list group policies | @@ -39,6 +41,7 @@ All URIs are relative to */api/v1* | [**listUsers**](AuthApi.md#listUsers) | **GET** /auth/users | list users | | [**login**](AuthApi.md#login) | **POST** /auth/login | perform a login | | [**oauthCallback**](AuthApi.md#oauthCallback) | **GET** /oidc/callback | | +| [**releaseTokenToMailbox**](AuthApi.md#releaseTokenToMailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. | | [**setGroupACL**](AuthApi.md#setGroupACL) | **POST** /auth/groups/{groupId}/acl | set ACL of group | | [**updatePolicy**](AuthApi.md#updatePolicy) | **PUT** /auth/policies/{policyId} | update policy | @@ -2165,6 +2168,133 @@ public class Example { | **429** | too many requests | - | | **0** | Internal Server Error | - | + +# **getTokenFromMailbox** +> AuthenticationToken getTokenFromMailbox(mailbox).execute(); + +receive the token after user has authenticated on redirect URL. + +### Example +```java +// Import classes: +import io.lakefs.clients.sdk.ApiClient; +import io.lakefs.clients.sdk.ApiException; +import io.lakefs.clients.sdk.Configuration; +import io.lakefs.clients.sdk.models.*; +import io.lakefs.clients.sdk.AuthApi; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("/api/v1"); + + AuthApi apiInstance = new AuthApi(defaultClient); + String mailbox = "mailbox_example"; // String | mailbox returned by getTokenRedirect + try { + AuthenticationToken result = apiInstance.getTokenFromMailbox(mailbox) + .execute(); + System.out.println(result); + } catch (ApiException e) { + System.err.println("Exception when calling AuthApi#getTokenFromMailbox"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} +``` + +### Parameters + +| Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **mailbox** | **String**| mailbox returned by getTokenRedirect | | + +### Return type + +[**AuthenticationToken**](AuthenticationToken.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **200** | user successfully logged in | - | +| **401** | Unauthorized | - | +| **404** | Resource Not Found | - | +| **429** | too many requests | - | +| **501** | Not Implemented | - | +| **0** | Internal Server Error | - | + + +# **getTokenRedirect** +> Error getTokenRedirect().execute(); + +start acquiring a token by logging in on a browser + +### Example +```java +// Import classes: +import io.lakefs.clients.sdk.ApiClient; +import io.lakefs.clients.sdk.ApiException; +import io.lakefs.clients.sdk.Configuration; +import io.lakefs.clients.sdk.models.*; +import io.lakefs.clients.sdk.AuthApi; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("/api/v1"); + + AuthApi apiInstance = new AuthApi(defaultClient); + try { + Error result = apiInstance.getTokenRedirect() + .execute(); + System.out.println(result); + } catch (ApiException e) { + System.err.println("Exception when calling AuthApi#getTokenRedirect"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**Error**](Error.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **303** | login on this page, await results on the mailbox URL | * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
| +| **401** | Unauthorized | - | +| **429** | too many requests | - | +| **501** | Not Implemented | - | +| **0** | Internal Server Error | - | + # **getUser** > User getUser(userId).execute(); @@ -3293,6 +3423,98 @@ No authorization required | **401** | failed to exchange authorization code for token | - | | **0** | Internal Server Error | - | + +# **releaseTokenToMailbox** +> releaseTokenToMailbox(loginRequestToken).execute(); + +release a token for the current (authenticated) user to the mailbox of this login request. + +### Example +```java +// Import classes: +import io.lakefs.clients.sdk.ApiClient; +import io.lakefs.clients.sdk.ApiException; +import io.lakefs.clients.sdk.Configuration; +import io.lakefs.clients.sdk.auth.*; +import io.lakefs.clients.sdk.models.*; +import io.lakefs.clients.sdk.AuthApi; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("/api/v1"); + + // Configure HTTP basic authorization: basic_auth + HttpBasicAuth basic_auth = (HttpBasicAuth) defaultClient.getAuthentication("basic_auth"); + basic_auth.setUsername("YOUR USERNAME"); + basic_auth.setPassword("YOUR PASSWORD"); + + // Configure API key authorization: cookie_auth + ApiKeyAuth cookie_auth = (ApiKeyAuth) defaultClient.getAuthentication("cookie_auth"); + cookie_auth.setApiKey("YOUR API KEY"); + // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) + //cookie_auth.setApiKeyPrefix("Token"); + + // Configure API key authorization: oidc_auth + ApiKeyAuth oidc_auth = (ApiKeyAuth) defaultClient.getAuthentication("oidc_auth"); + oidc_auth.setApiKey("YOUR API KEY"); + // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) + //oidc_auth.setApiKeyPrefix("Token"); + + // Configure API key authorization: saml_auth + ApiKeyAuth saml_auth = (ApiKeyAuth) defaultClient.getAuthentication("saml_auth"); + saml_auth.setApiKey("YOUR API KEY"); + // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) + //saml_auth.setApiKeyPrefix("Token"); + + // Configure HTTP bearer authorization: jwt_token + HttpBearerAuth jwt_token = (HttpBearerAuth) defaultClient.getAuthentication("jwt_token"); + jwt_token.setBearerToken("BEARER TOKEN"); + + AuthApi apiInstance = new AuthApi(defaultClient); + String loginRequestToken = "loginRequestToken_example"; // String | login request token returned by getTokenRedirect. + try { + apiInstance.releaseTokenToMailbox(loginRequestToken) + .execute(); + } catch (ApiException e) { + System.err.println("Exception when calling AuthApi#releaseTokenToMailbox"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} +``` + +### Parameters + +| Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **loginRequestToken** | **String**| login request token returned by getTokenRedirect. | | + +### Return type + +null (empty response body) + +### Authorization + +[basic_auth](../README.md#basic_auth), [cookie_auth](../README.md#cookie_auth), [oidc_auth](../README.md#oidc_auth), [saml_auth](../README.md#saml_auth), [jwt_token](../README.md#jwt_token) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **204** | token released | - | +| **401** | Unauthorized | - | +| **429** | too many requests | - | +| **501** | Not Implemented | - | +| **0** | Internal Server Error | - | + # **setGroupACL** > setGroupACL(groupId, ACL).execute(); diff --git a/clients/java/docs/ExperimentalApi.md b/clients/java/docs/ExperimentalApi.md index 13f27f77518..b572c3977f7 100644 --- a/clients/java/docs/ExperimentalApi.md +++ b/clients/java/docs/ExperimentalApi.md @@ -14,10 +14,13 @@ All URIs are relative to */api/v1* | [**getExternalPrincipal**](ExperimentalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id | | [**getLicense**](ExperimentalApi.md#getLicense) | **GET** /license | | | [**getPullRequest**](ExperimentalApi.md#getPullRequest) | **GET** /repositories/{repository}/pulls/{pull_request} | get pull request | +| [**getTokenFromMailbox**](ExperimentalApi.md#getTokenFromMailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. | +| [**getTokenRedirect**](ExperimentalApi.md#getTokenRedirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser | | [**hardResetBranch**](ExperimentalApi.md#hardResetBranch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch | | [**listPullRequests**](ExperimentalApi.md#listPullRequests) | **GET** /repositories/{repository}/pulls | list pull requests | | [**listUserExternalPrincipals**](ExperimentalApi.md#listUserExternalPrincipals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user | | [**mergePullRequest**](ExperimentalApi.md#mergePullRequest) | **PUT** /repositories/{repository}/pulls/{pull_request}/merge | merge pull request | +| [**releaseTokenToMailbox**](ExperimentalApi.md#releaseTokenToMailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. | | [**stsLogin**](ExperimentalApi.md#stsLogin) | **POST** /sts/login | perform a login with STS | | [**updateObjectUserMetadata**](ExperimentalApi.md#updateObjectUserMetadata) | **PUT** /repositories/{repository}/branches/{branch}/objects/stat/user_metadata | rewrite (all) object metadata | | [**updatePullRequest**](ExperimentalApi.md#updatePullRequest) | **PATCH** /repositories/{repository}/pulls/{pull_request} | update pull request | @@ -975,6 +978,133 @@ public class Example { | **429** | too many requests | - | | **0** | Internal Server Error | - | + +# **getTokenFromMailbox** +> AuthenticationToken getTokenFromMailbox(mailbox).execute(); + +receive the token after user has authenticated on redirect URL. + +### Example +```java +// Import classes: +import io.lakefs.clients.sdk.ApiClient; +import io.lakefs.clients.sdk.ApiException; +import io.lakefs.clients.sdk.Configuration; +import io.lakefs.clients.sdk.models.*; +import io.lakefs.clients.sdk.ExperimentalApi; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("/api/v1"); + + ExperimentalApi apiInstance = new ExperimentalApi(defaultClient); + String mailbox = "mailbox_example"; // String | mailbox returned by getTokenRedirect + try { + AuthenticationToken result = apiInstance.getTokenFromMailbox(mailbox) + .execute(); + System.out.println(result); + } catch (ApiException e) { + System.err.println("Exception when calling ExperimentalApi#getTokenFromMailbox"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} +``` + +### Parameters + +| Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **mailbox** | **String**| mailbox returned by getTokenRedirect | | + +### Return type + +[**AuthenticationToken**](AuthenticationToken.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **200** | user successfully logged in | - | +| **401** | Unauthorized | - | +| **404** | Resource Not Found | - | +| **429** | too many requests | - | +| **501** | Not Implemented | - | +| **0** | Internal Server Error | - | + + +# **getTokenRedirect** +> Error getTokenRedirect().execute(); + +start acquiring a token by logging in on a browser + +### Example +```java +// Import classes: +import io.lakefs.clients.sdk.ApiClient; +import io.lakefs.clients.sdk.ApiException; +import io.lakefs.clients.sdk.Configuration; +import io.lakefs.clients.sdk.models.*; +import io.lakefs.clients.sdk.ExperimentalApi; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("/api/v1"); + + ExperimentalApi apiInstance = new ExperimentalApi(defaultClient); + try { + Error result = apiInstance.getTokenRedirect() + .execute(); + System.out.println(result); + } catch (ApiException e) { + System.err.println("Exception when calling ExperimentalApi#getTokenRedirect"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} +``` + +### Parameters +This endpoint does not need any parameter. + +### Return type + +[**Error**](Error.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **303** | login on this page, await results on the mailbox URL | * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
| +| **401** | Unauthorized | - | +| **429** | too many requests | - | +| **501** | Not Implemented | - | +| **0** | Internal Server Error | - | + # **hardResetBranch** > hardResetBranch(repository, branch, ref).force(force).execute(); @@ -1384,6 +1514,98 @@ public class Example { | **429** | too many requests | - | | **0** | Internal Server Error | - | + +# **releaseTokenToMailbox** +> releaseTokenToMailbox(loginRequestToken).execute(); + +release a token for the current (authenticated) user to the mailbox of this login request. + +### Example +```java +// Import classes: +import io.lakefs.clients.sdk.ApiClient; +import io.lakefs.clients.sdk.ApiException; +import io.lakefs.clients.sdk.Configuration; +import io.lakefs.clients.sdk.auth.*; +import io.lakefs.clients.sdk.models.*; +import io.lakefs.clients.sdk.ExperimentalApi; + +public class Example { + public static void main(String[] args) { + ApiClient defaultClient = Configuration.getDefaultApiClient(); + defaultClient.setBasePath("/api/v1"); + + // Configure HTTP basic authorization: basic_auth + HttpBasicAuth basic_auth = (HttpBasicAuth) defaultClient.getAuthentication("basic_auth"); + basic_auth.setUsername("YOUR USERNAME"); + basic_auth.setPassword("YOUR PASSWORD"); + + // Configure API key authorization: cookie_auth + ApiKeyAuth cookie_auth = (ApiKeyAuth) defaultClient.getAuthentication("cookie_auth"); + cookie_auth.setApiKey("YOUR API KEY"); + // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) + //cookie_auth.setApiKeyPrefix("Token"); + + // Configure API key authorization: oidc_auth + ApiKeyAuth oidc_auth = (ApiKeyAuth) defaultClient.getAuthentication("oidc_auth"); + oidc_auth.setApiKey("YOUR API KEY"); + // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) + //oidc_auth.setApiKeyPrefix("Token"); + + // Configure API key authorization: saml_auth + ApiKeyAuth saml_auth = (ApiKeyAuth) defaultClient.getAuthentication("saml_auth"); + saml_auth.setApiKey("YOUR API KEY"); + // Uncomment the following line to set a prefix for the API key, e.g. "Token" (defaults to null) + //saml_auth.setApiKeyPrefix("Token"); + + // Configure HTTP bearer authorization: jwt_token + HttpBearerAuth jwt_token = (HttpBearerAuth) defaultClient.getAuthentication("jwt_token"); + jwt_token.setBearerToken("BEARER TOKEN"); + + ExperimentalApi apiInstance = new ExperimentalApi(defaultClient); + String loginRequestToken = "loginRequestToken_example"; // String | login request token returned by getTokenRedirect. + try { + apiInstance.releaseTokenToMailbox(loginRequestToken) + .execute(); + } catch (ApiException e) { + System.err.println("Exception when calling ExperimentalApi#releaseTokenToMailbox"); + System.err.println("Status code: " + e.getCode()); + System.err.println("Reason: " + e.getResponseBody()); + System.err.println("Response headers: " + e.getResponseHeaders()); + e.printStackTrace(); + } + } +} +``` + +### Parameters + +| Name | Type | Description | Notes | +|------------- | ------------- | ------------- | -------------| +| **loginRequestToken** | **String**| login request token returned by getTokenRedirect. | | + +### Return type + +null (empty response body) + +### Authorization + +[basic_auth](../README.md#basic_auth), [cookie_auth](../README.md#cookie_auth), [oidc_auth](../README.md#oidc_auth), [saml_auth](../README.md#saml_auth), [jwt_token](../README.md#jwt_token) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details +| Status code | Description | Response headers | +|-------------|-------------|------------------| +| **204** | token released | - | +| **401** | Unauthorized | - | +| **429** | too many requests | - | +| **501** | Not Implemented | - | +| **0** | Internal Server Error | - | + # **stsLogin** > AuthenticationToken stsLogin(stsAuthRequest).execute(); diff --git a/clients/java/src/main/java/io/lakefs/clients/sdk/AuthApi.java b/clients/java/src/main/java/io/lakefs/clients/sdk/AuthApi.java index c5daaafbf9d..f4427dbf2f8 100644 --- a/clients/java/src/main/java/io/lakefs/clients/sdk/AuthApi.java +++ b/clients/java/src/main/java/io/lakefs/clients/sdk/AuthApi.java @@ -4116,6 +4116,346 @@ public okhttp3.Call executeAsync(final ApiCallback _callback) throws Api public APIgetPolicyRequest getPolicy(String policyId) { return new APIgetPolicyRequest(policyId); } + private okhttp3.Call getTokenFromMailboxCall(String mailbox, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/auth/get-token/mailboxes/{mailbox}" + .replace("{" + "mailbox" + "}", localVarApiClient.escapeString(mailbox.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call getTokenFromMailboxValidateBeforeCall(String mailbox, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'mailbox' is set + if (mailbox == null) { + throw new ApiException("Missing the required parameter 'mailbox' when calling getTokenFromMailbox(Async)"); + } + + return getTokenFromMailboxCall(mailbox, _callback); + + } + + + private ApiResponse getTokenFromMailboxWithHttpInfo(String mailbox) throws ApiException { + okhttp3.Call localVarCall = getTokenFromMailboxValidateBeforeCall(mailbox, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + private okhttp3.Call getTokenFromMailboxAsync(String mailbox, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = getTokenFromMailboxValidateBeforeCall(mailbox, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + + public class APIgetTokenFromMailboxRequest { + private final String mailbox; + + private APIgetTokenFromMailboxRequest(String mailbox) { + this.mailbox = mailbox; + } + + /** + * Build call for getTokenFromMailbox + * @param _callback ApiCallback API callback + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { + return getTokenFromMailboxCall(mailbox, _callback); + } + + /** + * Execute getTokenFromMailbox request + * @return AuthenticationToken + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public AuthenticationToken execute() throws ApiException { + ApiResponse localVarResp = getTokenFromMailboxWithHttpInfo(mailbox); + return localVarResp.getData(); + } + + /** + * Execute getTokenFromMailbox request with HTTP info returned + * @return ApiResponse<AuthenticationToken> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public ApiResponse executeWithHttpInfo() throws ApiException { + return getTokenFromMailboxWithHttpInfo(mailbox); + } + + /** + * Execute getTokenFromMailbox request (asynchronously) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { + return getTokenFromMailboxAsync(mailbox, _callback); + } + } + + /** + * receive the token after user has authenticated on redirect URL. + * + * @param mailbox mailbox returned by getTokenRedirect (required) + * @return APIgetTokenFromMailboxRequest + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public APIgetTokenFromMailboxRequest getTokenFromMailbox(String mailbox) { + return new APIgetTokenFromMailboxRequest(mailbox); + } + private okhttp3.Call getTokenRedirectCall(final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/auth/get-token/start"; + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call getTokenRedirectValidateBeforeCall(final ApiCallback _callback) throws ApiException { + return getTokenRedirectCall(_callback); + + } + + + private ApiResponse getTokenRedirectWithHttpInfo() throws ApiException { + okhttp3.Call localVarCall = getTokenRedirectValidateBeforeCall(null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + private okhttp3.Call getTokenRedirectAsync(final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = getTokenRedirectValidateBeforeCall(_callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + + public class APIgetTokenRedirectRequest { + + private APIgetTokenRedirectRequest() { + } + + /** + * Build call for getTokenRedirect + * @param _callback ApiCallback API callback + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { + return getTokenRedirectCall(_callback); + } + + /** + * Execute getTokenRedirect request + * @return Error + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public Error execute() throws ApiException { + ApiResponse localVarResp = getTokenRedirectWithHttpInfo(); + return localVarResp.getData(); + } + + /** + * Execute getTokenRedirect request with HTTP info returned + * @return ApiResponse<Error> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public ApiResponse executeWithHttpInfo() throws ApiException { + return getTokenRedirectWithHttpInfo(); + } + + /** + * Execute getTokenRedirect request (asynchronously) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { + return getTokenRedirectAsync(_callback); + } + } + + /** + * start acquiring a token by logging in on a browser + * + * @return APIgetTokenRedirectRequest + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public APIgetTokenRedirectRequest getTokenRedirect() { + return new APIgetTokenRedirectRequest(); + } private okhttp3.Call getUserCall(String userId, final ApiCallback _callback) throws ApiException { String basePath = null; // Operation Servers @@ -6532,6 +6872,174 @@ public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiE public APIoauthCallbackRequest oauthCallback() { return new APIoauthCallbackRequest(); } + private okhttp3.Call releaseTokenToMailboxCall(String loginRequestToken, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/auth/get-token/release-token/{loginRequestToken}" + .replace("{" + "loginRequestToken" + "}", localVarApiClient.escapeString(loginRequestToken.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "basic_auth", "cookie_auth", "oidc_auth", "saml_auth", "jwt_token" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call releaseTokenToMailboxValidateBeforeCall(String loginRequestToken, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'loginRequestToken' is set + if (loginRequestToken == null) { + throw new ApiException("Missing the required parameter 'loginRequestToken' when calling releaseTokenToMailbox(Async)"); + } + + return releaseTokenToMailboxCall(loginRequestToken, _callback); + + } + + + private ApiResponse releaseTokenToMailboxWithHttpInfo(String loginRequestToken) throws ApiException { + okhttp3.Call localVarCall = releaseTokenToMailboxValidateBeforeCall(loginRequestToken, null); + return localVarApiClient.execute(localVarCall); + } + + private okhttp3.Call releaseTokenToMailboxAsync(String loginRequestToken, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = releaseTokenToMailboxValidateBeforeCall(loginRequestToken, _callback); + localVarApiClient.executeAsync(localVarCall, _callback); + return localVarCall; + } + + public class APIreleaseTokenToMailboxRequest { + private final String loginRequestToken; + + private APIreleaseTokenToMailboxRequest(String loginRequestToken) { + this.loginRequestToken = loginRequestToken; + } + + /** + * Build call for releaseTokenToMailbox + * @param _callback ApiCallback API callback + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { + return releaseTokenToMailboxCall(loginRequestToken, _callback); + } + + /** + * Execute releaseTokenToMailbox request + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public void execute() throws ApiException { + releaseTokenToMailboxWithHttpInfo(loginRequestToken); + } + + /** + * Execute releaseTokenToMailbox request with HTTP info returned + * @return ApiResponse<Void> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public ApiResponse executeWithHttpInfo() throws ApiException { + return releaseTokenToMailboxWithHttpInfo(loginRequestToken); + } + + /** + * Execute releaseTokenToMailbox request (asynchronously) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { + return releaseTokenToMailboxAsync(loginRequestToken, _callback); + } + } + + /** + * release a token for the current (authenticated) user to the mailbox of this login request. + * + * @param loginRequestToken login request token returned by getTokenRedirect. (required) + * @return APIreleaseTokenToMailboxRequest + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public APIreleaseTokenToMailboxRequest releaseTokenToMailbox(String loginRequestToken) { + return new APIreleaseTokenToMailboxRequest(loginRequestToken); + } private okhttp3.Call setGroupACLCall(String groupId, ACL ACL, final ApiCallback _callback) throws ApiException { String basePath = null; // Operation Servers diff --git a/clients/java/src/main/java/io/lakefs/clients/sdk/ExperimentalApi.java b/clients/java/src/main/java/io/lakefs/clients/sdk/ExperimentalApi.java index a84924e2950..34bee8f553d 100644 --- a/clients/java/src/main/java/io/lakefs/clients/sdk/ExperimentalApi.java +++ b/clients/java/src/main/java/io/lakefs/clients/sdk/ExperimentalApi.java @@ -2023,6 +2023,346 @@ public okhttp3.Call executeAsync(final ApiCallback _callback) throw public APIgetPullRequestRequest getPullRequest(String repository, String pullRequest) { return new APIgetPullRequestRequest(repository, pullRequest); } + private okhttp3.Call getTokenFromMailboxCall(String mailbox, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/auth/get-token/mailboxes/{mailbox}" + .replace("{" + "mailbox" + "}", localVarApiClient.escapeString(mailbox.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call getTokenFromMailboxValidateBeforeCall(String mailbox, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'mailbox' is set + if (mailbox == null) { + throw new ApiException("Missing the required parameter 'mailbox' when calling getTokenFromMailbox(Async)"); + } + + return getTokenFromMailboxCall(mailbox, _callback); + + } + + + private ApiResponse getTokenFromMailboxWithHttpInfo(String mailbox) throws ApiException { + okhttp3.Call localVarCall = getTokenFromMailboxValidateBeforeCall(mailbox, null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + private okhttp3.Call getTokenFromMailboxAsync(String mailbox, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = getTokenFromMailboxValidateBeforeCall(mailbox, _callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + + public class APIgetTokenFromMailboxRequest { + private final String mailbox; + + private APIgetTokenFromMailboxRequest(String mailbox) { + this.mailbox = mailbox; + } + + /** + * Build call for getTokenFromMailbox + * @param _callback ApiCallback API callback + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { + return getTokenFromMailboxCall(mailbox, _callback); + } + + /** + * Execute getTokenFromMailbox request + * @return AuthenticationToken + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public AuthenticationToken execute() throws ApiException { + ApiResponse localVarResp = getTokenFromMailboxWithHttpInfo(mailbox); + return localVarResp.getData(); + } + + /** + * Execute getTokenFromMailbox request with HTTP info returned + * @return ApiResponse<AuthenticationToken> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public ApiResponse executeWithHttpInfo() throws ApiException { + return getTokenFromMailboxWithHttpInfo(mailbox); + } + + /** + * Execute getTokenFromMailbox request (asynchronously) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { + return getTokenFromMailboxAsync(mailbox, _callback); + } + } + + /** + * receive the token after user has authenticated on redirect URL. + * + * @param mailbox mailbox returned by getTokenRedirect (required) + * @return APIgetTokenFromMailboxRequest + * @http.response.details + + + + + + + + +
Status Code Description Response Headers
200 user successfully logged in -
401 Unauthorized -
404 Resource Not Found -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public APIgetTokenFromMailboxRequest getTokenFromMailbox(String mailbox) { + return new APIgetTokenFromMailboxRequest(mailbox); + } + private okhttp3.Call getTokenRedirectCall(final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/auth/get-token/start"; + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call getTokenRedirectValidateBeforeCall(final ApiCallback _callback) throws ApiException { + return getTokenRedirectCall(_callback); + + } + + + private ApiResponse getTokenRedirectWithHttpInfo() throws ApiException { + okhttp3.Call localVarCall = getTokenRedirectValidateBeforeCall(null); + Type localVarReturnType = new TypeToken(){}.getType(); + return localVarApiClient.execute(localVarCall, localVarReturnType); + } + + private okhttp3.Call getTokenRedirectAsync(final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = getTokenRedirectValidateBeforeCall(_callback); + Type localVarReturnType = new TypeToken(){}.getType(); + localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); + return localVarCall; + } + + public class APIgetTokenRedirectRequest { + + private APIgetTokenRedirectRequest() { + } + + /** + * Build call for getTokenRedirect + * @param _callback ApiCallback API callback + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { + return getTokenRedirectCall(_callback); + } + + /** + * Execute getTokenRedirect request + * @return Error + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public Error execute() throws ApiException { + ApiResponse localVarResp = getTokenRedirectWithHttpInfo(); + return localVarResp.getData(); + } + + /** + * Execute getTokenRedirect request with HTTP info returned + * @return ApiResponse<Error> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public ApiResponse executeWithHttpInfo() throws ApiException { + return getTokenRedirectWithHttpInfo(); + } + + /** + * Execute getTokenRedirect request (asynchronously) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { + return getTokenRedirectAsync(_callback); + } + } + + /** + * start acquiring a token by logging in on a browser + * + * @return APIgetTokenRedirectRequest + * @http.response.details + + + + + + + +
Status Code Description Response Headers
303 login on this page, await results on the mailbox URL * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public APIgetTokenRedirectRequest getTokenRedirect() { + return new APIgetTokenRedirectRequest(); + } private okhttp3.Call hardResetBranchCall(String repository, String branch, String ref, Boolean force, final ApiCallback _callback) throws ApiException { String basePath = null; // Operation Servers @@ -2887,6 +3227,174 @@ public okhttp3.Call executeAsync(final ApiCallback _callback) throw public APImergePullRequestRequest mergePullRequest(String repository, String pullRequest) { return new APImergePullRequestRequest(repository, pullRequest); } + private okhttp3.Call releaseTokenToMailboxCall(String loginRequestToken, final ApiCallback _callback) throws ApiException { + String basePath = null; + // Operation Servers + String[] localBasePaths = new String[] { }; + + // Determine Base Path to Use + if (localCustomBaseUrl != null){ + basePath = localCustomBaseUrl; + } else if ( localBasePaths.length > 0 ) { + basePath = localBasePaths[localHostIndex]; + } else { + basePath = null; + } + + Object localVarPostBody = null; + + // create path and map variables + String localVarPath = "/auth/get-token/release-token/{loginRequestToken}" + .replace("{" + "loginRequestToken" + "}", localVarApiClient.escapeString(loginRequestToken.toString())); + + List localVarQueryParams = new ArrayList(); + List localVarCollectionQueryParams = new ArrayList(); + Map localVarHeaderParams = new HashMap(); + Map localVarCookieParams = new HashMap(); + Map localVarFormParams = new HashMap(); + + final String[] localVarAccepts = { + "application/json" + }; + final String localVarAccept = localVarApiClient.selectHeaderAccept(localVarAccepts); + if (localVarAccept != null) { + localVarHeaderParams.put("Accept", localVarAccept); + } + + final String[] localVarContentTypes = { + }; + final String localVarContentType = localVarApiClient.selectHeaderContentType(localVarContentTypes); + if (localVarContentType != null) { + localVarHeaderParams.put("Content-Type", localVarContentType); + } + + String[] localVarAuthNames = new String[] { "basic_auth", "cookie_auth", "oidc_auth", "saml_auth", "jwt_token" }; + return localVarApiClient.buildCall(basePath, localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); + } + + @SuppressWarnings("rawtypes") + private okhttp3.Call releaseTokenToMailboxValidateBeforeCall(String loginRequestToken, final ApiCallback _callback) throws ApiException { + // verify the required parameter 'loginRequestToken' is set + if (loginRequestToken == null) { + throw new ApiException("Missing the required parameter 'loginRequestToken' when calling releaseTokenToMailbox(Async)"); + } + + return releaseTokenToMailboxCall(loginRequestToken, _callback); + + } + + + private ApiResponse releaseTokenToMailboxWithHttpInfo(String loginRequestToken) throws ApiException { + okhttp3.Call localVarCall = releaseTokenToMailboxValidateBeforeCall(loginRequestToken, null); + return localVarApiClient.execute(localVarCall); + } + + private okhttp3.Call releaseTokenToMailboxAsync(String loginRequestToken, final ApiCallback _callback) throws ApiException { + + okhttp3.Call localVarCall = releaseTokenToMailboxValidateBeforeCall(loginRequestToken, _callback); + localVarApiClient.executeAsync(localVarCall, _callback); + return localVarCall; + } + + public class APIreleaseTokenToMailboxRequest { + private final String loginRequestToken; + + private APIreleaseTokenToMailboxRequest(String loginRequestToken) { + this.loginRequestToken = loginRequestToken; + } + + /** + * Build call for releaseTokenToMailbox + * @param _callback ApiCallback API callback + * @return Call to execute + * @throws ApiException If fail to serialize the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { + return releaseTokenToMailboxCall(loginRequestToken, _callback); + } + + /** + * Execute releaseTokenToMailbox request + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public void execute() throws ApiException { + releaseTokenToMailboxWithHttpInfo(loginRequestToken); + } + + /** + * Execute releaseTokenToMailbox request with HTTP info returned + * @return ApiResponse<Void> + * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public ApiResponse executeWithHttpInfo() throws ApiException { + return releaseTokenToMailboxWithHttpInfo(loginRequestToken); + } + + /** + * Execute releaseTokenToMailbox request (asynchronously) + * @param _callback The callback to be executed when the API call finishes + * @return The request call + * @throws ApiException If fail to process the API call, e.g. serializing the request body object + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { + return releaseTokenToMailboxAsync(loginRequestToken, _callback); + } + } + + /** + * release a token for the current (authenticated) user to the mailbox of this login request. + * + * @param loginRequestToken login request token returned by getTokenRedirect. (required) + * @return APIreleaseTokenToMailboxRequest + * @http.response.details + + + + + + + +
Status Code Description Response Headers
204 token released -
401 Unauthorized -
429 too many requests -
501 Not Implemented -
0 Internal Server Error -
+ */ + public APIreleaseTokenToMailboxRequest releaseTokenToMailbox(String loginRequestToken) { + return new APIreleaseTokenToMailboxRequest(loginRequestToken); + } private okhttp3.Call stsLoginCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { String basePath = null; // Operation Servers diff --git a/clients/java/src/test/java/io/lakefs/clients/sdk/AuthApiTest.java b/clients/java/src/test/java/io/lakefs/clients/sdk/AuthApiTest.java index b3b0f732993..a2b4946aca6 100644 --- a/clients/java/src/test/java/io/lakefs/clients/sdk/AuthApiTest.java +++ b/clients/java/src/test/java/io/lakefs/clients/sdk/AuthApiTest.java @@ -364,6 +364,31 @@ public void getPolicyTest() throws ApiException { // TODO: test validations } + /** + * receive the token after user has authenticated on redirect URL. + * + * @throws ApiException if the Api call fails + */ + @Test + public void getTokenFromMailboxTest() throws ApiException { + String mailbox = null; + AuthenticationToken response = api.getTokenFromMailbox(mailbox) + .execute(); + // TODO: test validations + } + + /** + * start acquiring a token by logging in on a browser + * + * @throws ApiException if the Api call fails + */ + @Test + public void getTokenRedirectTest() throws ApiException { + Error response = api.getTokenRedirect() + .execute(); + // TODO: test validations + } + /** * get user * @@ -571,6 +596,19 @@ public void oauthCallbackTest() throws ApiException { // TODO: test validations } + /** + * release a token for the current (authenticated) user to the mailbox of this login request. + * + * @throws ApiException if the Api call fails + */ + @Test + public void releaseTokenToMailboxTest() throws ApiException { + String loginRequestToken = null; + api.releaseTokenToMailbox(loginRequestToken) + .execute(); + // TODO: test validations + } + /** * set ACL of group * diff --git a/clients/java/src/test/java/io/lakefs/clients/sdk/ExperimentalApiTest.java b/clients/java/src/test/java/io/lakefs/clients/sdk/ExperimentalApiTest.java index b93d3180d65..22800a9b0c3 100644 --- a/clients/java/src/test/java/io/lakefs/clients/sdk/ExperimentalApiTest.java +++ b/clients/java/src/test/java/io/lakefs/clients/sdk/ExperimentalApiTest.java @@ -209,6 +209,31 @@ public void getPullRequestTest() throws ApiException { // TODO: test validations } + /** + * receive the token after user has authenticated on redirect URL. + * + * @throws ApiException if the Api call fails + */ + @Test + public void getTokenFromMailboxTest() throws ApiException { + String mailbox = null; + AuthenticationToken response = api.getTokenFromMailbox(mailbox) + .execute(); + // TODO: test validations + } + + /** + * start acquiring a token by logging in on a browser + * + * @throws ApiException if the Api call fails + */ + @Test + public void getTokenRedirectTest() throws ApiException { + Error response = api.getTokenRedirect() + .execute(); + // TODO: test validations + } + /** * hard reset branch * @@ -282,6 +307,19 @@ public void mergePullRequestTest() throws ApiException { // TODO: test validations } + /** + * release a token for the current (authenticated) user to the mailbox of this login request. + * + * @throws ApiException if the Api call fails + */ + @Test + public void releaseTokenToMailboxTest() throws ApiException { + String loginRequestToken = null; + api.releaseTokenToMailbox(loginRequestToken) + .execute(); + // TODO: test validations + } + /** * perform a login with STS * diff --git a/clients/python/README.md b/clients/python/README.md index 46a1f6ff576..d6ca0af0bcb 100644 --- a/clients/python/README.md +++ b/clients/python/README.md @@ -146,6 +146,8 @@ Class | Method | HTTP request | Description *AuthApi* | [**get_group**](docs/AuthApi.md#get_group) | **GET** /auth/groups/{groupId} | get group *AuthApi* | [**get_group_acl**](docs/AuthApi.md#get_group_acl) | **GET** /auth/groups/{groupId}/acl | get ACL of group *AuthApi* | [**get_policy**](docs/AuthApi.md#get_policy) | **GET** /auth/policies/{policyId} | get policy +*AuthApi* | [**get_token_from_mailbox**](docs/AuthApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +*AuthApi* | [**get_token_redirect**](docs/AuthApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser *AuthApi* | [**get_user**](docs/AuthApi.md#get_user) | **GET** /auth/users/{userId} | get user *AuthApi* | [**list_group_members**](docs/AuthApi.md#list_group_members) | **GET** /auth/groups/{groupId}/members | list group members *AuthApi* | [**list_group_policies**](docs/AuthApi.md#list_group_policies) | **GET** /auth/groups/{groupId}/policies | list group policies @@ -158,6 +160,7 @@ Class | Method | HTTP request | Description *AuthApi* | [**list_users**](docs/AuthApi.md#list_users) | **GET** /auth/users | list users *AuthApi* | [**login**](docs/AuthApi.md#login) | **POST** /auth/login | perform a login *AuthApi* | [**oauth_callback**](docs/AuthApi.md#oauth_callback) | **GET** /oidc/callback | +*AuthApi* | [**release_token_to_mailbox**](docs/AuthApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. *AuthApi* | [**set_group_acl**](docs/AuthApi.md#set_group_acl) | **POST** /auth/groups/{groupId}/acl | set ACL of group *AuthApi* | [**update_policy**](docs/AuthApi.md#update_policy) | **PUT** /auth/policies/{policyId} | update policy *BranchesApi* | [**cherry_pick**](docs/BranchesApi.md#cherry_pick) | **POST** /repositories/{repository}/branches/{branch}/cherry-pick | Replay the changes from the given commit on the branch @@ -181,10 +184,13 @@ Class | Method | HTTP request | Description *ExperimentalApi* | [**get_external_principal**](docs/ExperimentalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id *ExperimentalApi* | [**get_license**](docs/ExperimentalApi.md#get_license) | **GET** /license | *ExperimentalApi* | [**get_pull_request**](docs/ExperimentalApi.md#get_pull_request) | **GET** /repositories/{repository}/pulls/{pull_request} | get pull request +*ExperimentalApi* | [**get_token_from_mailbox**](docs/ExperimentalApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +*ExperimentalApi* | [**get_token_redirect**](docs/ExperimentalApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser *ExperimentalApi* | [**hard_reset_branch**](docs/ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch *ExperimentalApi* | [**list_pull_requests**](docs/ExperimentalApi.md#list_pull_requests) | **GET** /repositories/{repository}/pulls | list pull requests *ExperimentalApi* | [**list_user_external_principals**](docs/ExperimentalApi.md#list_user_external_principals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user *ExperimentalApi* | [**merge_pull_request**](docs/ExperimentalApi.md#merge_pull_request) | **PUT** /repositories/{repository}/pulls/{pull_request}/merge | merge pull request +*ExperimentalApi* | [**release_token_to_mailbox**](docs/ExperimentalApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. *ExperimentalApi* | [**sts_login**](docs/ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS *ExperimentalApi* | [**update_object_user_metadata**](docs/ExperimentalApi.md#update_object_user_metadata) | **PUT** /repositories/{repository}/branches/{branch}/objects/stat/user_metadata | rewrite (all) object metadata *ExperimentalApi* | [**update_pull_request**](docs/ExperimentalApi.md#update_pull_request) | **PATCH** /repositories/{repository}/pulls/{pull_request} | update pull request diff --git a/clients/python/docs/AuthApi.md b/clients/python/docs/AuthApi.md index fb033ee66ed..fbea419cf43 100644 --- a/clients/python/docs/AuthApi.md +++ b/clients/python/docs/AuthApi.md @@ -27,6 +27,8 @@ Method | HTTP request | Description [**get_group**](AuthApi.md#get_group) | **GET** /auth/groups/{groupId} | get group [**get_group_acl**](AuthApi.md#get_group_acl) | **GET** /auth/groups/{groupId}/acl | get ACL of group [**get_policy**](AuthApi.md#get_policy) | **GET** /auth/policies/{policyId} | get policy +[**get_token_from_mailbox**](AuthApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +[**get_token_redirect**](AuthApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser [**get_user**](AuthApi.md#get_user) | **GET** /auth/users/{userId} | get user [**list_group_members**](AuthApi.md#list_group_members) | **GET** /auth/groups/{groupId}/members | list group members [**list_group_policies**](AuthApi.md#list_group_policies) | **GET** /auth/groups/{groupId}/policies | list group policies @@ -39,6 +41,7 @@ Method | HTTP request | Description [**list_users**](AuthApi.md#list_users) | **GET** /auth/users | list users [**login**](AuthApi.md#login) | **POST** /auth/login | perform a login [**oauth_callback**](AuthApi.md#oauth_callback) | **GET** /oidc/callback | +[**release_token_to_mailbox**](AuthApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. [**set_group_acl**](AuthApi.md#set_group_acl) | **POST** /auth/groups/{groupId}/acl | set ACL of group [**update_policy**](AuthApi.md#update_policy) | **PUT** /auth/policies/{policyId} | update policy @@ -2522,6 +2525,147 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **get_token_from_mailbox** +> AuthenticationToken get_token_from_mailbox(mailbox) + +receive the token after user has authenticated on redirect URL. + +### Example + + +```python +import time +import os +import lakefs_sdk +from lakefs_sdk.models.authentication_token import AuthenticationToken +from lakefs_sdk.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api/v1 +# See configuration.py for a list of all supported configuration parameters. +configuration = lakefs_sdk.Configuration( + host = "/api/v1" +) + + +# Enter a context with an instance of the API client +with lakefs_sdk.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = lakefs_sdk.AuthApi(api_client) + mailbox = 'mailbox_example' # str | mailbox returned by getTokenRedirect + + try: + # receive the token after user has authenticated on redirect URL. + api_response = api_instance.get_token_from_mailbox(mailbox) + print("The response of AuthApi->get_token_from_mailbox:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling AuthApi->get_token_from_mailbox: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **mailbox** | **str**| mailbox returned by getTokenRedirect | + +### Return type + +[**AuthenticationToken**](AuthenticationToken.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | user successfully logged in | - | +**401** | Unauthorized | - | +**404** | Resource Not Found | - | +**429** | too many requests | - | +**501** | Not Implemented | - | +**0** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **get_token_redirect** +> Error get_token_redirect() + +start acquiring a token by logging in on a browser + +### Example + + +```python +import time +import os +import lakefs_sdk +from lakefs_sdk.models.error import Error +from lakefs_sdk.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api/v1 +# See configuration.py for a list of all supported configuration parameters. +configuration = lakefs_sdk.Configuration( + host = "/api/v1" +) + + +# Enter a context with an instance of the API client +with lakefs_sdk.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = lakefs_sdk.AuthApi(api_client) + + try: + # start acquiring a token by logging in on a browser + api_response = api_instance.get_token_redirect() + print("The response of AuthApi->get_token_redirect:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling AuthApi->get_token_redirect: %s\n" % e) +``` + + + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +[**Error**](Error.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**303** | login on this page, await results on the mailbox URL | * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
| +**401** | Unauthorized | - | +**429** | too many requests | - | +**501** | Not Implemented | - | +**0** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **get_user** > User get_user(user_id) @@ -3805,6 +3949,113 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **release_token_to_mailbox** +> release_token_to_mailbox(login_request_token) + +release a token for the current (authenticated) user to the mailbox of this login request. + +### Example + +* Basic Authentication (basic_auth): +* Api Key Authentication (cookie_auth): +* Api Key Authentication (oidc_auth): +* Api Key Authentication (saml_auth): +* Bearer (JWT) Authentication (jwt_token): + +```python +import time +import os +import lakefs_sdk +from lakefs_sdk.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api/v1 +# See configuration.py for a list of all supported configuration parameters. +configuration = lakefs_sdk.Configuration( + host = "/api/v1" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure HTTP basic authorization: basic_auth +configuration = lakefs_sdk.Configuration( + username = os.environ["USERNAME"], + password = os.environ["PASSWORD"] +) + +# Configure API key authorization: cookie_auth +configuration.api_key['cookie_auth'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['cookie_auth'] = 'Bearer' + +# Configure API key authorization: oidc_auth +configuration.api_key['oidc_auth'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['oidc_auth'] = 'Bearer' + +# Configure API key authorization: saml_auth +configuration.api_key['saml_auth'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['saml_auth'] = 'Bearer' + +# Configure Bearer authorization (JWT): jwt_token +configuration = lakefs_sdk.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with lakefs_sdk.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = lakefs_sdk.AuthApi(api_client) + login_request_token = 'login_request_token_example' # str | login request token returned by getTokenRedirect. + + try: + # release a token for the current (authenticated) user to the mailbox of this login request. + api_instance.release_token_to_mailbox(login_request_token) + except Exception as e: + print("Exception when calling AuthApi->release_token_to_mailbox: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **login_request_token** | **str**| login request token returned by getTokenRedirect. | + +### Return type + +void (empty response body) + +### Authorization + +[basic_auth](../README.md#basic_auth), [cookie_auth](../README.md#cookie_auth), [oidc_auth](../README.md#oidc_auth), [saml_auth](../README.md#saml_auth), [jwt_token](../README.md#jwt_token) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**204** | token released | - | +**401** | Unauthorized | - | +**429** | too many requests | - | +**501** | Not Implemented | - | +**0** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **set_group_acl** > set_group_acl(group_id, acl) diff --git a/clients/python/docs/ExperimentalApi.md b/clients/python/docs/ExperimentalApi.md index eb17786639c..87ebf9be5fb 100644 --- a/clients/python/docs/ExperimentalApi.md +++ b/clients/python/docs/ExperimentalApi.md @@ -14,10 +14,13 @@ Method | HTTP request | Description [**get_external_principal**](ExperimentalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id [**get_license**](ExperimentalApi.md#get_license) | **GET** /license | [**get_pull_request**](ExperimentalApi.md#get_pull_request) | **GET** /repositories/{repository}/pulls/{pull_request} | get pull request +[**get_token_from_mailbox**](ExperimentalApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +[**get_token_redirect**](ExperimentalApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser [**hard_reset_branch**](ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch [**list_pull_requests**](ExperimentalApi.md#list_pull_requests) | **GET** /repositories/{repository}/pulls | list pull requests [**list_user_external_principals**](ExperimentalApi.md#list_user_external_principals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user [**merge_pull_request**](ExperimentalApi.md#merge_pull_request) | **PUT** /repositories/{repository}/pulls/{pull_request}/merge | merge pull request +[**release_token_to_mailbox**](ExperimentalApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. [**sts_login**](ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS [**update_object_user_metadata**](ExperimentalApi.md#update_object_user_metadata) | **PUT** /repositories/{repository}/branches/{branch}/objects/stat/user_metadata | rewrite (all) object metadata [**update_pull_request**](ExperimentalApi.md#update_pull_request) | **PATCH** /repositories/{repository}/pulls/{pull_request} | update pull request @@ -1128,6 +1131,147 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **get_token_from_mailbox** +> AuthenticationToken get_token_from_mailbox(mailbox) + +receive the token after user has authenticated on redirect URL. + +### Example + + +```python +import time +import os +import lakefs_sdk +from lakefs_sdk.models.authentication_token import AuthenticationToken +from lakefs_sdk.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api/v1 +# See configuration.py for a list of all supported configuration parameters. +configuration = lakefs_sdk.Configuration( + host = "/api/v1" +) + + +# Enter a context with an instance of the API client +with lakefs_sdk.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = lakefs_sdk.ExperimentalApi(api_client) + mailbox = 'mailbox_example' # str | mailbox returned by getTokenRedirect + + try: + # receive the token after user has authenticated on redirect URL. + api_response = api_instance.get_token_from_mailbox(mailbox) + print("The response of ExperimentalApi->get_token_from_mailbox:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling ExperimentalApi->get_token_from_mailbox: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **mailbox** | **str**| mailbox returned by getTokenRedirect | + +### Return type + +[**AuthenticationToken**](AuthenticationToken.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**200** | user successfully logged in | - | +**401** | Unauthorized | - | +**404** | Resource Not Found | - | +**429** | too many requests | - | +**501** | Not Implemented | - | +**0** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + +# **get_token_redirect** +> Error get_token_redirect() + +start acquiring a token by logging in on a browser + +### Example + + +```python +import time +import os +import lakefs_sdk +from lakefs_sdk.models.error import Error +from lakefs_sdk.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api/v1 +# See configuration.py for a list of all supported configuration parameters. +configuration = lakefs_sdk.Configuration( + host = "/api/v1" +) + + +# Enter a context with an instance of the API client +with lakefs_sdk.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = lakefs_sdk.ExperimentalApi(api_client) + + try: + # start acquiring a token by logging in on a browser + api_response = api_instance.get_token_redirect() + print("The response of ExperimentalApi->get_token_redirect:\n") + pprint(api_response) + except Exception as e: + print("Exception when calling ExperimentalApi->get_token_redirect: %s\n" % e) +``` + + + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +[**Error**](Error.md) + +### Authorization + +No authorization required + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**303** | login on this page, await results on the mailbox URL | * Location - redirect to S3
* X-LakeFS-Mailbox - GET the token from this mailbox. Keep the mailbox SECRET!
| +**401** | Unauthorized | - | +**429** | too many requests | - | +**501** | Not Implemented | - | +**0** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **hard_reset_branch** > hard_reset_branch(repository, branch, ref, force=force) @@ -1595,6 +1739,113 @@ Name | Type | Description | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +# **release_token_to_mailbox** +> release_token_to_mailbox(login_request_token) + +release a token for the current (authenticated) user to the mailbox of this login request. + +### Example + +* Basic Authentication (basic_auth): +* Api Key Authentication (cookie_auth): +* Api Key Authentication (oidc_auth): +* Api Key Authentication (saml_auth): +* Bearer (JWT) Authentication (jwt_token): + +```python +import time +import os +import lakefs_sdk +from lakefs_sdk.rest import ApiException +from pprint import pprint + +# Defining the host is optional and defaults to /api/v1 +# See configuration.py for a list of all supported configuration parameters. +configuration = lakefs_sdk.Configuration( + host = "/api/v1" +) + +# The client must configure the authentication and authorization parameters +# in accordance with the API server security policy. +# Examples for each auth method are provided below, use the example that +# satisfies your auth use case. + +# Configure HTTP basic authorization: basic_auth +configuration = lakefs_sdk.Configuration( + username = os.environ["USERNAME"], + password = os.environ["PASSWORD"] +) + +# Configure API key authorization: cookie_auth +configuration.api_key['cookie_auth'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['cookie_auth'] = 'Bearer' + +# Configure API key authorization: oidc_auth +configuration.api_key['oidc_auth'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['oidc_auth'] = 'Bearer' + +# Configure API key authorization: saml_auth +configuration.api_key['saml_auth'] = os.environ["API_KEY"] + +# Uncomment below to setup prefix (e.g. Bearer) for API key, if needed +# configuration.api_key_prefix['saml_auth'] = 'Bearer' + +# Configure Bearer authorization (JWT): jwt_token +configuration = lakefs_sdk.Configuration( + access_token = os.environ["BEARER_TOKEN"] +) + +# Enter a context with an instance of the API client +with lakefs_sdk.ApiClient(configuration) as api_client: + # Create an instance of the API class + api_instance = lakefs_sdk.ExperimentalApi(api_client) + login_request_token = 'login_request_token_example' # str | login request token returned by getTokenRedirect. + + try: + # release a token for the current (authenticated) user to the mailbox of this login request. + api_instance.release_token_to_mailbox(login_request_token) + except Exception as e: + print("Exception when calling ExperimentalApi->release_token_to_mailbox: %s\n" % e) +``` + + + +### Parameters + + +Name | Type | Description | Notes +------------- | ------------- | ------------- | ------------- + **login_request_token** | **str**| login request token returned by getTokenRedirect. | + +### Return type + +void (empty response body) + +### Authorization + +[basic_auth](../README.md#basic_auth), [cookie_auth](../README.md#cookie_auth), [oidc_auth](../README.md#oidc_auth), [saml_auth](../README.md#saml_auth), [jwt_token](../README.md#jwt_token) + +### HTTP request headers + + - **Content-Type**: Not defined + - **Accept**: application/json + +### HTTP response details + +| Status code | Description | Response headers | +|-------------|-------------|------------------| +**204** | token released | - | +**401** | Unauthorized | - | +**429** | too many requests | - | +**501** | Not Implemented | - | +**0** | Internal Server Error | - | + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + # **sts_login** > AuthenticationToken sts_login(sts_auth_request) diff --git a/clients/python/lakefs_sdk/api/auth_api.py b/clients/python/lakefs_sdk/api/auth_api.py index d2f8cfb1d9b..57dcb0e4880 100644 --- a/clients/python/lakefs_sdk/api/auth_api.py +++ b/clients/python/lakefs_sdk/api/auth_api.py @@ -24,9 +24,9 @@ from typing_extensions import Annotated try: - from pydantic.v1 import Field, StrictBool, StrictStr, conint + from pydantic.v1 import Field, StrictBool, StrictStr, conint, constr except ImportError: - from pydantic import Field, StrictBool, StrictStr, conint + from pydantic import Field, StrictBool, StrictStr, conint, constr from typing import Optional @@ -3370,6 +3370,281 @@ def get_policy_with_http_info(self, policy_id : StrictStr, **kwargs) -> ApiRespo collection_formats=_collection_formats, _request_auth=_params.get('_request_auth')) + @validate_arguments + def get_token_from_mailbox(self, mailbox : Annotated[StrictStr, Field(..., description="mailbox returned by getTokenRedirect")], **kwargs) -> AuthenticationToken: # noqa: E501 + """receive the token after user has authenticated on redirect URL. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_from_mailbox(mailbox, async_req=True) + >>> result = thread.get() + + :param mailbox: mailbox returned by getTokenRedirect (required) + :type mailbox: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _request_timeout: timeout setting for this request. + If one number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: AuthenticationToken + """ + kwargs['_return_http_data_only'] = True + if '_preload_content' in kwargs: + message = "Error! Please call the get_token_from_mailbox_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + raise ValueError(message) + return self.get_token_from_mailbox_with_http_info(mailbox, **kwargs) # noqa: E501 + + @validate_arguments + def get_token_from_mailbox_with_http_info(self, mailbox : Annotated[StrictStr, Field(..., description="mailbox returned by getTokenRedirect")], **kwargs) -> ApiResponse: # noqa: E501 + """receive the token after user has authenticated on redirect URL. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_from_mailbox_with_http_info(mailbox, async_req=True) + >>> result = thread.get() + + :param mailbox: mailbox returned by getTokenRedirect (required) + :type mailbox: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _preload_content: if False, the ApiResponse.data will + be set to none and raw_data will store the + HTTP response body without reading/decoding. + Default is True. + :type _preload_content: bool, optional + :param _return_http_data_only: response data instead of ApiResponse + object with status code, headers, etc + :type _return_http_data_only: bool, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :type _request_auth: dict, optional + :type _content_type: string, optional: force content-type for the request + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: tuple(AuthenticationToken, status_code(int), headers(HTTPHeaderDict)) + """ + + _params = locals() + + _all_params = [ + 'mailbox' + ] + _all_params.extend( + [ + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout', + '_request_auth', + '_content_type', + '_headers' + ] + ) + + # validate the arguments + for _key, _val in _params['kwargs'].items(): + if _key not in _all_params: + raise ApiTypeError( + "Got an unexpected keyword argument '%s'" + " to method get_token_from_mailbox" % _key + ) + _params[_key] = _val + del _params['kwargs'] + + _collection_formats = {} + + # process the path parameters + _path_params = {} + if _params['mailbox']: + _path_params['mailbox'] = _params['mailbox'] + + + # process the query parameters + _query_params = [] + # process the header parameters + _header_params = dict(_params.get('_headers', {})) + # process the form parameters + _form_params = [] + _files = {} + # process the body parameter + _body_params = None + # set the HTTP header `Accept` + _header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # authentication setting + _auth_settings = [] # noqa: E501 + + _response_types_map = { + '200': "AuthenticationToken", + '401': "Error", + '404': "Error", + '429': None, + '501': "Error", + } + + return self.api_client.call_api( + '/auth/get-token/mailboxes/{mailbox}', 'GET', + _path_params, + _query_params, + _header_params, + body=_body_params, + post_params=_form_params, + files=_files, + response_types_map=_response_types_map, + auth_settings=_auth_settings, + async_req=_params.get('async_req'), + _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 + _preload_content=_params.get('_preload_content', True), + _request_timeout=_params.get('_request_timeout'), + collection_formats=_collection_formats, + _request_auth=_params.get('_request_auth')) + + @validate_arguments + def get_token_redirect(self, **kwargs) -> Error: # noqa: E501 + """start acquiring a token by logging in on a browser # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_redirect(async_req=True) + >>> result = thread.get() + + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _request_timeout: timeout setting for this request. + If one number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: Error + """ + kwargs['_return_http_data_only'] = True + if '_preload_content' in kwargs: + message = "Error! Please call the get_token_redirect_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + raise ValueError(message) + return self.get_token_redirect_with_http_info(**kwargs) # noqa: E501 + + @validate_arguments + def get_token_redirect_with_http_info(self, **kwargs) -> ApiResponse: # noqa: E501 + """start acquiring a token by logging in on a browser # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_redirect_with_http_info(async_req=True) + >>> result = thread.get() + + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _preload_content: if False, the ApiResponse.data will + be set to none and raw_data will store the + HTTP response body without reading/decoding. + Default is True. + :type _preload_content: bool, optional + :param _return_http_data_only: response data instead of ApiResponse + object with status code, headers, etc + :type _return_http_data_only: bool, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :type _request_auth: dict, optional + :type _content_type: string, optional: force content-type for the request + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: tuple(Error, status_code(int), headers(HTTPHeaderDict)) + """ + + _params = locals() + + _all_params = [ + ] + _all_params.extend( + [ + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout', + '_request_auth', + '_content_type', + '_headers' + ] + ) + + # validate the arguments + for _key, _val in _params['kwargs'].items(): + if _key not in _all_params: + raise ApiTypeError( + "Got an unexpected keyword argument '%s'" + " to method get_token_redirect" % _key + ) + _params[_key] = _val + del _params['kwargs'] + + _collection_formats = {} + + # process the path parameters + _path_params = {} + + # process the query parameters + _query_params = [] + # process the header parameters + _header_params = dict(_params.get('_headers', {})) + # process the form parameters + _form_params = [] + _files = {} + # process the body parameter + _body_params = None + # set the HTTP header `Accept` + _header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # authentication setting + _auth_settings = [] # noqa: E501 + + _response_types_map = { + '303': None, + '401': "Error", + '429': None, + '501': "Error", + } + + return self.api_client.call_api( + '/auth/get-token/start', 'GET', + _path_params, + _query_params, + _header_params, + body=_body_params, + post_params=_form_params, + files=_files, + response_types_map=_response_types_map, + auth_settings=_auth_settings, + async_req=_params.get('async_req'), + _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 + _preload_content=_params.get('_preload_content', True), + _request_timeout=_params.get('_request_timeout'), + collection_formats=_collection_formats, + _request_auth=_params.get('_request_auth')) + @validate_arguments def get_user(self, user_id : StrictStr, **kwargs) -> User: # noqa: E501 """get user # noqa: E501 @@ -5254,6 +5529,142 @@ def oauth_callback_with_http_info(self, **kwargs) -> ApiResponse: # noqa: E501 collection_formats=_collection_formats, _request_auth=_params.get('_request_auth')) + @validate_arguments + def release_token_to_mailbox(self, login_request_token : Annotated[constr(strict=True, max_length=1024), Field(..., description="login request token returned by getTokenRedirect.")], **kwargs) -> None: # noqa: E501 + """release a token for the current (authenticated) user to the mailbox of this login request. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.release_token_to_mailbox(login_request_token, async_req=True) + >>> result = thread.get() + + :param login_request_token: login request token returned by getTokenRedirect. (required) + :type login_request_token: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _request_timeout: timeout setting for this request. + If one number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: None + """ + kwargs['_return_http_data_only'] = True + if '_preload_content' in kwargs: + message = "Error! Please call the release_token_to_mailbox_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + raise ValueError(message) + return self.release_token_to_mailbox_with_http_info(login_request_token, **kwargs) # noqa: E501 + + @validate_arguments + def release_token_to_mailbox_with_http_info(self, login_request_token : Annotated[constr(strict=True, max_length=1024), Field(..., description="login request token returned by getTokenRedirect.")], **kwargs) -> ApiResponse: # noqa: E501 + """release a token for the current (authenticated) user to the mailbox of this login request. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.release_token_to_mailbox_with_http_info(login_request_token, async_req=True) + >>> result = thread.get() + + :param login_request_token: login request token returned by getTokenRedirect. (required) + :type login_request_token: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _preload_content: if False, the ApiResponse.data will + be set to none and raw_data will store the + HTTP response body without reading/decoding. + Default is True. + :type _preload_content: bool, optional + :param _return_http_data_only: response data instead of ApiResponse + object with status code, headers, etc + :type _return_http_data_only: bool, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :type _request_auth: dict, optional + :type _content_type: string, optional: force content-type for the request + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: None + """ + + _params = locals() + + _all_params = [ + 'login_request_token' + ] + _all_params.extend( + [ + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout', + '_request_auth', + '_content_type', + '_headers' + ] + ) + + # validate the arguments + for _key, _val in _params['kwargs'].items(): + if _key not in _all_params: + raise ApiTypeError( + "Got an unexpected keyword argument '%s'" + " to method release_token_to_mailbox" % _key + ) + _params[_key] = _val + del _params['kwargs'] + + _collection_formats = {} + + # process the path parameters + _path_params = {} + if _params['login_request_token']: + _path_params['loginRequestToken'] = _params['login_request_token'] + + + # process the query parameters + _query_params = [] + # process the header parameters + _header_params = dict(_params.get('_headers', {})) + # process the form parameters + _form_params = [] + _files = {} + # process the body parameter + _body_params = None + # set the HTTP header `Accept` + _header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # authentication setting + _auth_settings = ['basic_auth', 'cookie_auth', 'oidc_auth', 'saml_auth', 'jwt_token'] # noqa: E501 + + _response_types_map = {} + + return self.api_client.call_api( + '/auth/get-token/release-token/{loginRequestToken}', 'GET', + _path_params, + _query_params, + _header_params, + body=_body_params, + post_params=_form_params, + files=_files, + response_types_map=_response_types_map, + auth_settings=_auth_settings, + async_req=_params.get('async_req'), + _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 + _preload_content=_params.get('_preload_content', True), + _request_timeout=_params.get('_request_timeout'), + collection_formats=_collection_formats, + _request_auth=_params.get('_request_auth')) + @validate_arguments def set_group_acl(self, group_id : StrictStr, acl : ACL, **kwargs) -> None: # noqa: E501 """set ACL of group # noqa: E501 diff --git a/clients/python/lakefs_sdk/api/experimental_api.py b/clients/python/lakefs_sdk/api/experimental_api.py index aa1f5bb073a..9c330898e05 100644 --- a/clients/python/lakefs_sdk/api/experimental_api.py +++ b/clients/python/lakefs_sdk/api/experimental_api.py @@ -24,15 +24,16 @@ from typing_extensions import Annotated try: - from pydantic.v1 import Field, StrictBool, StrictInt, StrictStr, conint + from pydantic.v1 import Field, StrictBool, StrictInt, StrictStr, conint, constr except ImportError: - from pydantic import Field, StrictBool, StrictInt, StrictStr, conint + from pydantic import Field, StrictBool, StrictInt, StrictStr, conint, constr from typing import Optional from lakefs_sdk.models.abort_presign_multipart_upload import AbortPresignMultipartUpload from lakefs_sdk.models.authentication_token import AuthenticationToken from lakefs_sdk.models.complete_presign_multipart_upload import CompletePresignMultipartUpload +from lakefs_sdk.models.error import Error from lakefs_sdk.models.external_login_information import ExternalLoginInformation from lakefs_sdk.models.external_principal import ExternalPrincipal from lakefs_sdk.models.external_principal_creation import ExternalPrincipalCreation @@ -1638,6 +1639,281 @@ def get_pull_request_with_http_info(self, repository : StrictStr, pull_request : collection_formats=_collection_formats, _request_auth=_params.get('_request_auth')) + @validate_arguments + def get_token_from_mailbox(self, mailbox : Annotated[StrictStr, Field(..., description="mailbox returned by getTokenRedirect")], **kwargs) -> AuthenticationToken: # noqa: E501 + """receive the token after user has authenticated on redirect URL. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_from_mailbox(mailbox, async_req=True) + >>> result = thread.get() + + :param mailbox: mailbox returned by getTokenRedirect (required) + :type mailbox: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _request_timeout: timeout setting for this request. + If one number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: AuthenticationToken + """ + kwargs['_return_http_data_only'] = True + if '_preload_content' in kwargs: + message = "Error! Please call the get_token_from_mailbox_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + raise ValueError(message) + return self.get_token_from_mailbox_with_http_info(mailbox, **kwargs) # noqa: E501 + + @validate_arguments + def get_token_from_mailbox_with_http_info(self, mailbox : Annotated[StrictStr, Field(..., description="mailbox returned by getTokenRedirect")], **kwargs) -> ApiResponse: # noqa: E501 + """receive the token after user has authenticated on redirect URL. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_from_mailbox_with_http_info(mailbox, async_req=True) + >>> result = thread.get() + + :param mailbox: mailbox returned by getTokenRedirect (required) + :type mailbox: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _preload_content: if False, the ApiResponse.data will + be set to none and raw_data will store the + HTTP response body without reading/decoding. + Default is True. + :type _preload_content: bool, optional + :param _return_http_data_only: response data instead of ApiResponse + object with status code, headers, etc + :type _return_http_data_only: bool, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :type _request_auth: dict, optional + :type _content_type: string, optional: force content-type for the request + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: tuple(AuthenticationToken, status_code(int), headers(HTTPHeaderDict)) + """ + + _params = locals() + + _all_params = [ + 'mailbox' + ] + _all_params.extend( + [ + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout', + '_request_auth', + '_content_type', + '_headers' + ] + ) + + # validate the arguments + for _key, _val in _params['kwargs'].items(): + if _key not in _all_params: + raise ApiTypeError( + "Got an unexpected keyword argument '%s'" + " to method get_token_from_mailbox" % _key + ) + _params[_key] = _val + del _params['kwargs'] + + _collection_formats = {} + + # process the path parameters + _path_params = {} + if _params['mailbox']: + _path_params['mailbox'] = _params['mailbox'] + + + # process the query parameters + _query_params = [] + # process the header parameters + _header_params = dict(_params.get('_headers', {})) + # process the form parameters + _form_params = [] + _files = {} + # process the body parameter + _body_params = None + # set the HTTP header `Accept` + _header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # authentication setting + _auth_settings = [] # noqa: E501 + + _response_types_map = { + '200': "AuthenticationToken", + '401': "Error", + '404': "Error", + '429': None, + '501': "Error", + } + + return self.api_client.call_api( + '/auth/get-token/mailboxes/{mailbox}', 'GET', + _path_params, + _query_params, + _header_params, + body=_body_params, + post_params=_form_params, + files=_files, + response_types_map=_response_types_map, + auth_settings=_auth_settings, + async_req=_params.get('async_req'), + _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 + _preload_content=_params.get('_preload_content', True), + _request_timeout=_params.get('_request_timeout'), + collection_formats=_collection_formats, + _request_auth=_params.get('_request_auth')) + + @validate_arguments + def get_token_redirect(self, **kwargs) -> Error: # noqa: E501 + """start acquiring a token by logging in on a browser # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_redirect(async_req=True) + >>> result = thread.get() + + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _request_timeout: timeout setting for this request. + If one number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: Error + """ + kwargs['_return_http_data_only'] = True + if '_preload_content' in kwargs: + message = "Error! Please call the get_token_redirect_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + raise ValueError(message) + return self.get_token_redirect_with_http_info(**kwargs) # noqa: E501 + + @validate_arguments + def get_token_redirect_with_http_info(self, **kwargs) -> ApiResponse: # noqa: E501 + """start acquiring a token by logging in on a browser # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.get_token_redirect_with_http_info(async_req=True) + >>> result = thread.get() + + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _preload_content: if False, the ApiResponse.data will + be set to none and raw_data will store the + HTTP response body without reading/decoding. + Default is True. + :type _preload_content: bool, optional + :param _return_http_data_only: response data instead of ApiResponse + object with status code, headers, etc + :type _return_http_data_only: bool, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :type _request_auth: dict, optional + :type _content_type: string, optional: force content-type for the request + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: tuple(Error, status_code(int), headers(HTTPHeaderDict)) + """ + + _params = locals() + + _all_params = [ + ] + _all_params.extend( + [ + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout', + '_request_auth', + '_content_type', + '_headers' + ] + ) + + # validate the arguments + for _key, _val in _params['kwargs'].items(): + if _key not in _all_params: + raise ApiTypeError( + "Got an unexpected keyword argument '%s'" + " to method get_token_redirect" % _key + ) + _params[_key] = _val + del _params['kwargs'] + + _collection_formats = {} + + # process the path parameters + _path_params = {} + + # process the query parameters + _query_params = [] + # process the header parameters + _header_params = dict(_params.get('_headers', {})) + # process the form parameters + _form_params = [] + _files = {} + # process the body parameter + _body_params = None + # set the HTTP header `Accept` + _header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # authentication setting + _auth_settings = [] # noqa: E501 + + _response_types_map = { + '303': None, + '401': "Error", + '429': None, + '501': "Error", + } + + return self.api_client.call_api( + '/auth/get-token/start', 'GET', + _path_params, + _query_params, + _header_params, + body=_body_params, + post_params=_form_params, + files=_files, + response_types_map=_response_types_map, + auth_settings=_auth_settings, + async_req=_params.get('async_req'), + _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 + _preload_content=_params.get('_preload_content', True), + _request_timeout=_params.get('_request_timeout'), + collection_formats=_collection_formats, + _request_auth=_params.get('_request_auth')) + @validate_arguments def hard_reset_branch(self, repository : StrictStr, branch : StrictStr, ref : Annotated[StrictStr, Field(..., description="After reset, branch will point at this reference.")], force : Optional[StrictBool] = None, **kwargs) -> None: # noqa: E501 """hard reset branch # noqa: E501 @@ -2291,6 +2567,142 @@ def merge_pull_request_with_http_info(self, repository : StrictStr, pull_request collection_formats=_collection_formats, _request_auth=_params.get('_request_auth')) + @validate_arguments + def release_token_to_mailbox(self, login_request_token : Annotated[constr(strict=True, max_length=1024), Field(..., description="login request token returned by getTokenRedirect.")], **kwargs) -> None: # noqa: E501 + """release a token for the current (authenticated) user to the mailbox of this login request. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.release_token_to_mailbox(login_request_token, async_req=True) + >>> result = thread.get() + + :param login_request_token: login request token returned by getTokenRedirect. (required) + :type login_request_token: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _request_timeout: timeout setting for this request. + If one number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: None + """ + kwargs['_return_http_data_only'] = True + if '_preload_content' in kwargs: + message = "Error! Please call the release_token_to_mailbox_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data" # noqa: E501 + raise ValueError(message) + return self.release_token_to_mailbox_with_http_info(login_request_token, **kwargs) # noqa: E501 + + @validate_arguments + def release_token_to_mailbox_with_http_info(self, login_request_token : Annotated[constr(strict=True, max_length=1024), Field(..., description="login request token returned by getTokenRedirect.")], **kwargs) -> ApiResponse: # noqa: E501 + """release a token for the current (authenticated) user to the mailbox of this login request. # noqa: E501 + + This method makes a synchronous HTTP request by default. To make an + asynchronous HTTP request, please pass async_req=True + + >>> thread = api.release_token_to_mailbox_with_http_info(login_request_token, async_req=True) + >>> result = thread.get() + + :param login_request_token: login request token returned by getTokenRedirect. (required) + :type login_request_token: str + :param async_req: Whether to execute the request asynchronously. + :type async_req: bool, optional + :param _preload_content: if False, the ApiResponse.data will + be set to none and raw_data will store the + HTTP response body without reading/decoding. + Default is True. + :type _preload_content: bool, optional + :param _return_http_data_only: response data instead of ApiResponse + object with status code, headers, etc + :type _return_http_data_only: bool, optional + :param _request_timeout: timeout setting for this request. If one + number provided, it will be total request + timeout. It can also be a pair (tuple) of + (connection, read) timeouts. + :param _request_auth: set to override the auth_settings for an a single + request; this effectively ignores the authentication + in the spec for a single request. + :type _request_auth: dict, optional + :type _content_type: string, optional: force content-type for the request + :return: Returns the result object. + If the method is called asynchronously, + returns the request thread. + :rtype: None + """ + + _params = locals() + + _all_params = [ + 'login_request_token' + ] + _all_params.extend( + [ + 'async_req', + '_return_http_data_only', + '_preload_content', + '_request_timeout', + '_request_auth', + '_content_type', + '_headers' + ] + ) + + # validate the arguments + for _key, _val in _params['kwargs'].items(): + if _key not in _all_params: + raise ApiTypeError( + "Got an unexpected keyword argument '%s'" + " to method release_token_to_mailbox" % _key + ) + _params[_key] = _val + del _params['kwargs'] + + _collection_formats = {} + + # process the path parameters + _path_params = {} + if _params['login_request_token']: + _path_params['loginRequestToken'] = _params['login_request_token'] + + + # process the query parameters + _query_params = [] + # process the header parameters + _header_params = dict(_params.get('_headers', {})) + # process the form parameters + _form_params = [] + _files = {} + # process the body parameter + _body_params = None + # set the HTTP header `Accept` + _header_params['Accept'] = self.api_client.select_header_accept( + ['application/json']) # noqa: E501 + + # authentication setting + _auth_settings = ['basic_auth', 'cookie_auth', 'oidc_auth', 'saml_auth', 'jwt_token'] # noqa: E501 + + _response_types_map = {} + + return self.api_client.call_api( + '/auth/get-token/release-token/{loginRequestToken}', 'GET', + _path_params, + _query_params, + _header_params, + body=_body_params, + post_params=_form_params, + files=_files, + response_types_map=_response_types_map, + auth_settings=_auth_settings, + async_req=_params.get('async_req'), + _return_http_data_only=_params.get('_return_http_data_only'), # noqa: E501 + _preload_content=_params.get('_preload_content', True), + _request_timeout=_params.get('_request_timeout'), + collection_formats=_collection_formats, + _request_auth=_params.get('_request_auth')) + @validate_arguments def sts_login(self, sts_auth_request : StsAuthRequest, **kwargs) -> AuthenticationToken: # noqa: E501 """perform a login with STS # noqa: E501 diff --git a/clients/python/test/test_auth_api.py b/clients/python/test/test_auth_api.py index e8c9558e69c..8183c7d81e9 100644 --- a/clients/python/test/test_auth_api.py +++ b/clients/python/test/test_auth_api.py @@ -188,6 +188,20 @@ def test_get_policy(self) -> None: """ pass + def test_get_token_from_mailbox(self) -> None: + """Test case for get_token_from_mailbox + + receive the token after user has authenticated on redirect URL. # noqa: E501 + """ + pass + + def test_get_token_redirect(self) -> None: + """Test case for get_token_redirect + + start acquiring a token by logging in on a browser # noqa: E501 + """ + pass + def test_get_user(self) -> None: """Test case for get_user @@ -271,6 +285,13 @@ def test_oauth_callback(self) -> None: """ pass + def test_release_token_to_mailbox(self) -> None: + """Test case for release_token_to_mailbox + + release a token for the current (authenticated) user to the mailbox of this login request. # noqa: E501 + """ + pass + def test_set_group_acl(self) -> None: """Test case for set_group_acl diff --git a/clients/python/test/test_experimental_api.py b/clients/python/test/test_experimental_api.py index 732b68e5eb5..937e8573fc0 100644 --- a/clients/python/test/test_experimental_api.py +++ b/clients/python/test/test_experimental_api.py @@ -96,6 +96,20 @@ def test_get_pull_request(self) -> None: """ pass + def test_get_token_from_mailbox(self) -> None: + """Test case for get_token_from_mailbox + + receive the token after user has authenticated on redirect URL. # noqa: E501 + """ + pass + + def test_get_token_redirect(self) -> None: + """Test case for get_token_redirect + + start acquiring a token by logging in on a browser # noqa: E501 + """ + pass + def test_hard_reset_branch(self) -> None: """Test case for hard_reset_branch @@ -124,6 +138,13 @@ def test_merge_pull_request(self) -> None: """ pass + def test_release_token_to_mailbox(self) -> None: + """Test case for release_token_to_mailbox + + release a token for the current (authenticated) user to the mailbox of this login request. # noqa: E501 + """ + pass + def test_sts_login(self) -> None: """Test case for sts_login diff --git a/clients/rust/README.md b/clients/rust/README.md index a691a7eca71..33a419ac1df 100644 --- a/clients/rust/README.md +++ b/clients/rust/README.md @@ -53,6 +53,8 @@ Class | Method | HTTP request | Description *AuthApi* | [**get_group**](docs/AuthApi.md#get_group) | **GET** /auth/groups/{groupId} | get group *AuthApi* | [**get_group_acl**](docs/AuthApi.md#get_group_acl) | **GET** /auth/groups/{groupId}/acl | get ACL of group *AuthApi* | [**get_policy**](docs/AuthApi.md#get_policy) | **GET** /auth/policies/{policyId} | get policy +*AuthApi* | [**get_token_from_mailbox**](docs/AuthApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +*AuthApi* | [**get_token_redirect**](docs/AuthApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser *AuthApi* | [**get_user**](docs/AuthApi.md#get_user) | **GET** /auth/users/{userId} | get user *AuthApi* | [**list_group_members**](docs/AuthApi.md#list_group_members) | **GET** /auth/groups/{groupId}/members | list group members *AuthApi* | [**list_group_policies**](docs/AuthApi.md#list_group_policies) | **GET** /auth/groups/{groupId}/policies | list group policies @@ -65,6 +67,7 @@ Class | Method | HTTP request | Description *AuthApi* | [**list_users**](docs/AuthApi.md#list_users) | **GET** /auth/users | list users *AuthApi* | [**login**](docs/AuthApi.md#login) | **POST** /auth/login | perform a login *AuthApi* | [**oauth_callback**](docs/AuthApi.md#oauth_callback) | **GET** /oidc/callback | +*AuthApi* | [**release_token_to_mailbox**](docs/AuthApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. *AuthApi* | [**set_group_acl**](docs/AuthApi.md#set_group_acl) | **POST** /auth/groups/{groupId}/acl | set ACL of group *AuthApi* | [**update_policy**](docs/AuthApi.md#update_policy) | **PUT** /auth/policies/{policyId} | update policy *BranchesApi* | [**cherry_pick**](docs/BranchesApi.md#cherry_pick) | **POST** /repositories/{repository}/branches/{branch}/cherry-pick | Replay the changes from the given commit on the branch @@ -88,10 +91,13 @@ Class | Method | HTTP request | Description *ExperimentalApi* | [**get_external_principal**](docs/ExperimentalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id *ExperimentalApi* | [**get_license**](docs/ExperimentalApi.md#get_license) | **GET** /license | *ExperimentalApi* | [**get_pull_request**](docs/ExperimentalApi.md#get_pull_request) | **GET** /repositories/{repository}/pulls/{pull_request} | get pull request +*ExperimentalApi* | [**get_token_from_mailbox**](docs/ExperimentalApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +*ExperimentalApi* | [**get_token_redirect**](docs/ExperimentalApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser *ExperimentalApi* | [**hard_reset_branch**](docs/ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch *ExperimentalApi* | [**list_pull_requests**](docs/ExperimentalApi.md#list_pull_requests) | **GET** /repositories/{repository}/pulls | list pull requests *ExperimentalApi* | [**list_user_external_principals**](docs/ExperimentalApi.md#list_user_external_principals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user *ExperimentalApi* | [**merge_pull_request**](docs/ExperimentalApi.md#merge_pull_request) | **PUT** /repositories/{repository}/pulls/{pull_request}/merge | merge pull request +*ExperimentalApi* | [**release_token_to_mailbox**](docs/ExperimentalApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. *ExperimentalApi* | [**sts_login**](docs/ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS *ExperimentalApi* | [**update_object_user_metadata**](docs/ExperimentalApi.md#update_object_user_metadata) | **PUT** /repositories/{repository}/branches/{branch}/objects/stat/user_metadata | rewrite (all) object metadata *ExperimentalApi* | [**update_pull_request**](docs/ExperimentalApi.md#update_pull_request) | **PATCH** /repositories/{repository}/pulls/{pull_request} | update pull request diff --git a/clients/rust/docs/AuthApi.md b/clients/rust/docs/AuthApi.md index af3cea62cc5..8b4a7195edf 100644 --- a/clients/rust/docs/AuthApi.md +++ b/clients/rust/docs/AuthApi.md @@ -27,6 +27,8 @@ Method | HTTP request | Description [**get_group**](AuthApi.md#get_group) | **GET** /auth/groups/{groupId} | get group [**get_group_acl**](AuthApi.md#get_group_acl) | **GET** /auth/groups/{groupId}/acl | get ACL of group [**get_policy**](AuthApi.md#get_policy) | **GET** /auth/policies/{policyId} | get policy +[**get_token_from_mailbox**](AuthApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +[**get_token_redirect**](AuthApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser [**get_user**](AuthApi.md#get_user) | **GET** /auth/users/{userId} | get user [**list_group_members**](AuthApi.md#list_group_members) | **GET** /auth/groups/{groupId}/members | list group members [**list_group_policies**](AuthApi.md#list_group_policies) | **GET** /auth/groups/{groupId}/policies | list group policies @@ -39,6 +41,7 @@ Method | HTTP request | Description [**list_users**](AuthApi.md#list_users) | **GET** /auth/users | list users [**login**](AuthApi.md#login) | **POST** /auth/login | perform a login [**oauth_callback**](AuthApi.md#oauth_callback) | **GET** /oidc/callback | +[**release_token_to_mailbox**](AuthApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. [**set_group_acl**](AuthApi.md#set_group_acl) | **POST** /auth/groups/{groupId}/acl | set ACL of group [**update_policy**](AuthApi.md#update_policy) | **PUT** /auth/policies/{policyId} | update policy @@ -696,6 +699,59 @@ Name | Type | Description | Required | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## get_token_from_mailbox + +> models::AuthenticationToken get_token_from_mailbox(mailbox) +receive the token after user has authenticated on redirect URL. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**mailbox** | **String** | mailbox returned by getTokenRedirect | [required] | + +### Return type + +[**models::AuthenticationToken**](AuthenticationToken.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_token_redirect + +> models::Error get_token_redirect() +start acquiring a token by logging in on a browser + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +[**models::Error**](Error.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## get_user > models::User get_user(user_id) @@ -1054,6 +1110,34 @@ No authorization required [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## release_token_to_mailbox + +> release_token_to_mailbox(login_request_token) +release a token for the current (authenticated) user to the mailbox of this login request. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**login_request_token** | **String** | login request token returned by getTokenRedirect. | [required] | + +### Return type + + (empty response body) + +### Authorization + +[basic_auth](../README.md#basic_auth), [cookie_auth](../README.md#cookie_auth), [oidc_auth](../README.md#oidc_auth), [saml_auth](../README.md#saml_auth), [jwt_token](../README.md#jwt_token) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## set_group_acl > set_group_acl(group_id, acl) diff --git a/clients/rust/docs/ExperimentalApi.md b/clients/rust/docs/ExperimentalApi.md index 3066fa8938e..f732723328e 100644 --- a/clients/rust/docs/ExperimentalApi.md +++ b/clients/rust/docs/ExperimentalApi.md @@ -14,10 +14,13 @@ Method | HTTP request | Description [**get_external_principal**](ExperimentalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id [**get_license**](ExperimentalApi.md#get_license) | **GET** /license | [**get_pull_request**](ExperimentalApi.md#get_pull_request) | **GET** /repositories/{repository}/pulls/{pull_request} | get pull request +[**get_token_from_mailbox**](ExperimentalApi.md#get_token_from_mailbox) | **GET** /auth/get-token/mailboxes/{mailbox} | receive the token after user has authenticated on redirect URL. +[**get_token_redirect**](ExperimentalApi.md#get_token_redirect) | **GET** /auth/get-token/start | start acquiring a token by logging in on a browser [**hard_reset_branch**](ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch [**list_pull_requests**](ExperimentalApi.md#list_pull_requests) | **GET** /repositories/{repository}/pulls | list pull requests [**list_user_external_principals**](ExperimentalApi.md#list_user_external_principals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user [**merge_pull_request**](ExperimentalApi.md#merge_pull_request) | **PUT** /repositories/{repository}/pulls/{pull_request}/merge | merge pull request +[**release_token_to_mailbox**](ExperimentalApi.md#release_token_to_mailbox) | **GET** /auth/get-token/release-token/{loginRequestToken} | release a token for the current (authenticated) user to the mailbox of this login request. [**sts_login**](ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS [**update_object_user_metadata**](ExperimentalApi.md#update_object_user_metadata) | **PUT** /repositories/{repository}/branches/{branch}/objects/stat/user_metadata | rewrite (all) object metadata [**update_pull_request**](ExperimentalApi.md#update_pull_request) | **PATCH** /repositories/{repository}/pulls/{pull_request} | update pull request @@ -327,6 +330,59 @@ Name | Type | Description | Required | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## get_token_from_mailbox + +> models::AuthenticationToken get_token_from_mailbox(mailbox) +receive the token after user has authenticated on redirect URL. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**mailbox** | **String** | mailbox returned by getTokenRedirect | [required] | + +### Return type + +[**models::AuthenticationToken**](AuthenticationToken.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + +## get_token_redirect + +> models::Error get_token_redirect() +start acquiring a token by logging in on a browser + +### Parameters + +This endpoint does not need any parameter. + +### Return type + +[**models::Error**](Error.md) + +### Authorization + +No authorization required + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## hard_reset_branch > hard_reset_branch(repository, branch, r#ref, force) @@ -452,6 +508,34 @@ Name | Type | Description | Required | Notes [[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) +## release_token_to_mailbox + +> release_token_to_mailbox(login_request_token) +release a token for the current (authenticated) user to the mailbox of this login request. + +### Parameters + + +Name | Type | Description | Required | Notes +------------- | ------------- | ------------- | ------------- | ------------- +**login_request_token** | **String** | login request token returned by getTokenRedirect. | [required] | + +### Return type + + (empty response body) + +### Authorization + +[basic_auth](../README.md#basic_auth), [cookie_auth](../README.md#cookie_auth), [oidc_auth](../README.md#oidc_auth), [saml_auth](../README.md#saml_auth), [jwt_token](../README.md#jwt_token) + +### HTTP request headers + +- **Content-Type**: Not defined +- **Accept**: application/json + +[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md) + + ## sts_login > models::AuthenticationToken sts_login(sts_auth_request) diff --git a/clients/rust/src/apis/auth_api.rs b/clients/rust/src/apis/auth_api.rs index 0ff65bcde05..0456ef29fac 100644 --- a/clients/rust/src/apis/auth_api.rs +++ b/clients/rust/src/apis/auth_api.rs @@ -269,6 +269,29 @@ pub enum GetPolicyError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`get_token_from_mailbox`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetTokenFromMailboxError { + Status401(models::Error), + Status404(models::Error), + Status429(), + Status501(models::Error), + DefaultResponse(models::Error), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_token_redirect`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetTokenRedirectError { + Status401(models::Error), + Status429(), + Status501(models::Error), + DefaultResponse(models::Error), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`get_user`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -394,6 +417,17 @@ pub enum OauthCallbackError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`release_token_to_mailbox`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ReleaseTokenToMailboxError { + Status401(models::Error), + Status429(), + Status501(models::Error), + DefaultResponse(models::Error), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`set_group_acl`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -1179,6 +1213,60 @@ pub async fn get_policy(configuration: &configuration::Configuration, policy_id: } } +pub async fn get_token_from_mailbox(configuration: &configuration::Configuration, mailbox: &str) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/auth/get-token/mailboxes/{mailbox}", local_var_configuration.base_path, mailbox=crate::apis::urlencode(mailbox)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn get_token_redirect(configuration: &configuration::Configuration, ) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/auth/get-token/start", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + pub async fn get_user(configuration: &configuration::Configuration, user_id: &str) -> Result> { let local_var_configuration = configuration; @@ -1648,6 +1736,39 @@ pub async fn oauth_callback(configuration: &configuration::Configuration, ) -> R } } +pub async fn release_token_to_mailbox(configuration: &configuration::Configuration, login_request_token: &str) -> Result<(), Error> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/auth/get-token/release-token/{loginRequestToken}", local_var_configuration.base_path, loginRequestToken=crate::apis::urlencode(login_request_token)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + pub async fn set_group_acl(configuration: &configuration::Configuration, group_id: &str, acl: models::Acl) -> Result<(), Error> { let local_var_configuration = configuration; diff --git a/clients/rust/src/apis/experimental_api.rs b/clients/rust/src/apis/experimental_api.rs index d2d192a18aa..642858d0ff8 100644 --- a/clients/rust/src/apis/experimental_api.rs +++ b/clients/rust/src/apis/experimental_api.rs @@ -135,6 +135,29 @@ pub enum GetPullRequestError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`get_token_from_mailbox`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetTokenFromMailboxError { + Status401(models::Error), + Status404(models::Error), + Status429(), + Status501(models::Error), + DefaultResponse(models::Error), + UnknownValue(serde_json::Value), +} + +/// struct for typed errors of method [`get_token_redirect`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GetTokenRedirectError { + Status401(models::Error), + Status429(), + Status501(models::Error), + DefaultResponse(models::Error), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`hard_reset_branch`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -185,6 +208,17 @@ pub enum MergePullRequestError { UnknownValue(serde_json::Value), } +/// struct for typed errors of method [`release_token_to_mailbox`] +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum ReleaseTokenToMailboxError { + Status401(models::Error), + Status429(), + Status501(models::Error), + DefaultResponse(models::Error), + UnknownValue(serde_json::Value), +} + /// struct for typed errors of method [`sts_login`] #[derive(Debug, Clone, Serialize, Deserialize)] #[serde(untagged)] @@ -585,6 +619,60 @@ pub async fn get_pull_request(configuration: &configuration::Configuration, repo } } +pub async fn get_token_from_mailbox(configuration: &configuration::Configuration, mailbox: &str) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/auth/get-token/mailboxes/{mailbox}", local_var_configuration.base_path, mailbox=crate::apis::urlencode(mailbox)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + +pub async fn get_token_redirect(configuration: &configuration::Configuration, ) -> Result> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/auth/get-token/start", local_var_configuration.base_path); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + serde_json::from_str(&local_var_content).map_err(Error::from) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + /// Relocate branch to refer to ref. Branch must not contain uncommitted data. pub async fn hard_reset_branch(configuration: &configuration::Configuration, repository: &str, branch: &str, r#ref: &str, force: Option) -> Result<(), Error> { let local_var_configuration = configuration; @@ -743,6 +831,39 @@ pub async fn merge_pull_request(configuration: &configuration::Configuration, re } } +pub async fn release_token_to_mailbox(configuration: &configuration::Configuration, login_request_token: &str) -> Result<(), Error> { + let local_var_configuration = configuration; + + let local_var_client = &local_var_configuration.client; + + let local_var_uri_str = format!("{}/auth/get-token/release-token/{loginRequestToken}", local_var_configuration.base_path, loginRequestToken=crate::apis::urlencode(login_request_token)); + let mut local_var_req_builder = local_var_client.request(reqwest::Method::GET, local_var_uri_str.as_str()); + + if let Some(ref local_var_user_agent) = local_var_configuration.user_agent { + local_var_req_builder = local_var_req_builder.header(reqwest::header::USER_AGENT, local_var_user_agent.clone()); + } + if let Some(ref local_var_auth_conf) = local_var_configuration.basic_auth { + local_var_req_builder = local_var_req_builder.basic_auth(local_var_auth_conf.0.to_owned(), local_var_auth_conf.1.to_owned()); + }; + if let Some(ref local_var_token) = local_var_configuration.bearer_access_token { + local_var_req_builder = local_var_req_builder.bearer_auth(local_var_token.to_owned()); + }; + + let local_var_req = local_var_req_builder.build()?; + let local_var_resp = local_var_client.execute(local_var_req).await?; + + let local_var_status = local_var_resp.status(); + let local_var_content = local_var_resp.text().await?; + + if !local_var_status.is_client_error() && !local_var_status.is_server_error() { + Ok(()) + } else { + let local_var_entity: Option = serde_json::from_str(&local_var_content).ok(); + let local_var_error = ResponseContent { status: local_var_status, content: local_var_content, entity: local_var_entity }; + Err(Error::ResponseError(local_var_error)) + } +} + pub async fn sts_login(configuration: &configuration::Configuration, sts_auth_request: models::StsAuthRequest) -> Result> { let local_var_configuration = configuration; diff --git a/clients/spark/sbt-launch.jar b/clients/spark/sbt-launch.jar new file mode 100644 index 00000000000..b2890257f1b Binary files /dev/null and b/clients/spark/sbt-launch.jar differ diff --git a/cmd/lakectl/cmd/fs_upload.go b/cmd/lakectl/cmd/fs_upload.go index 36957c80fa8..dcc2a1ddb46 100644 --- a/cmd/lakectl/cmd/fs_upload.go +++ b/cmd/lakectl/cmd/fs_upload.go @@ -58,7 +58,7 @@ var fsUploadCmd = &cobra.Command{ } }() - s := local.NewSyncManager(ctx, client, getHTTPClient(), local.Config{ + s := local.NewSyncManager(ctx, client, getHTTPClient(lakectlRetryPolicy), local.Config{ SyncFlags: syncFlags, SkipNonRegularFiles: cfg.Local.SkipNonRegularFiles, IncludePerm: false, @@ -100,7 +100,7 @@ func upload(ctx context.Context, client apigen.ClientWithResponsesInterface, sou }() objectPath := apiutil.Value(destURI.Path) if syncFlags.Presign { - return helpers.ClientUploadPreSign(ctx, client, getHTTPClient(), destURI.Repository, destURI.Ref, objectPath, nil, contentType, fp, syncFlags.PresignMultipart) + return helpers.ClientUploadPreSign(ctx, client, getHTTPClient(lakectlRetryPolicy), destURI.Repository, destURI.Ref, objectPath, nil, contentType, fp, syncFlags.PresignMultipart) } return helpers.ClientUpload(ctx, client, destURI.Repository, destURI.Ref, objectPath, nil, contentType, fp) } diff --git a/cmd/lakectl/cmd/local_checkout.go b/cmd/lakectl/cmd/local_checkout.go index 15b5081c35e..b6e92b12f15 100644 --- a/cmd/lakectl/cmd/local_checkout.go +++ b/cmd/lakectl/cmd/local_checkout.go @@ -57,7 +57,7 @@ func localCheckout(cmd *cobra.Command, localPath string, specifiedRef string, co currentBase := remote.WithRef(idx.AtHead) diffs := local.Undo(localDiff(cmd.Context(), client, currentBase, idx.LocalPath())) sigCtx := localHandleSyncInterrupt(cmd.Context(), idx, string(checkoutOperation)) - syncMgr := local.NewSyncManager(sigCtx, client, getHTTPClient(), buildLocalConfig(syncFlags, cfg)) + syncMgr := local.NewSyncManager(sigCtx, client, getHTTPClient(lakectlRetryPolicy), buildLocalConfig(syncFlags, cfg)) // confirm on local changes if confirmByFlag && len(diffs) > 0 { fmt.Println("Uncommitted changes exist, the operation will revert all changes on local directory.") diff --git a/cmd/lakectl/cmd/local_clone.go b/cmd/lakectl/cmd/local_clone.go index b72f83e8032..ceb7e402ab3 100644 --- a/cmd/lakectl/cmd/local_clone.go +++ b/cmd/lakectl/cmd/local_clone.go @@ -86,7 +86,7 @@ var localCloneCmd = &cobra.Command{ } sigCtx := localHandleSyncInterrupt(ctx, idx, string(cloneOperation)) syncFlags := getSyncFlags(cmd, client, remote.Repository) - s := local.NewSyncManager(sigCtx, client, getHTTPClient(), buildLocalConfig(syncFlags, cfg)) + s := local.NewSyncManager(sigCtx, client, getHTTPClient(lakectlRetryPolicy), buildLocalConfig(syncFlags, cfg)) err = s.Sync(localPath, stableRemote, ch) if err != nil { DieErr(err) diff --git a/cmd/lakectl/cmd/local_commit.go b/cmd/lakectl/cmd/local_commit.go index a8c0e6f4997..15ee6f1ab15 100644 --- a/cmd/lakectl/cmd/local_commit.go +++ b/cmd/lakectl/cmd/local_commit.go @@ -172,7 +172,7 @@ var localCommitCmd = &cobra.Command{ } sigCtx := localHandleSyncInterrupt(cmd.Context(), idx, string(commitOperation)) - s := local.NewSyncManager(sigCtx, client, getHTTPClient(), buildLocalConfig(syncFlags, cfg)) + s := local.NewSyncManager(sigCtx, client, getHTTPClient(lakectlRetryPolicy), buildLocalConfig(syncFlags, cfg)) err = s.Sync(idx.LocalPath(), remote, c) if err != nil { diff --git a/cmd/lakectl/cmd/local_pull.go b/cmd/lakectl/cmd/local_pull.go index 8690e53039d..4f9250130f2 100644 --- a/cmd/lakectl/cmd/local_pull.go +++ b/cmd/lakectl/cmd/local_pull.go @@ -66,7 +66,7 @@ var localPullCmd = &cobra.Command{ return nil }) sigCtx := localHandleSyncInterrupt(cmd.Context(), idx, string(pullOperation)) - s := local.NewSyncManager(sigCtx, client, getHTTPClient(), buildLocalConfig(syncFlags, cfg)) + s := local.NewSyncManager(sigCtx, client, getHTTPClient(lakectlRetryPolicy), buildLocalConfig(syncFlags, cfg)) err = s.Sync(idx.LocalPath(), newBase, c) if err != nil { diff --git a/cmd/lakectl/cmd/login.go b/cmd/lakectl/cmd/login.go new file mode 100644 index 00000000000..3ef8bfb88c9 --- /dev/null +++ b/cmd/lakectl/cmd/login.go @@ -0,0 +1,100 @@ +package cmd + +import ( + "context" + "fmt" + "net/http" + "net/url" + "slices" + "time" + + "github.com/skratchdot/open-golang/open" + "github.com/spf13/cobra" + "github.com/treeverse/lakefs/pkg/api/apigen" + "github.com/treeverse/lakefs/pkg/httputil" +) + +const ( + // TODO(ariels): Underline the link? + webLoginTemplate = `Opening {{.RedirectURL | blue | underline}} where you should log in. +If it does not open automatically, please try to open it manually and log in. +` + loggedInTemplate = ` +[{{.Time | green}}] {{"Logged in." | green | bold}} +` +) + +type webLoginParams struct { + RedirectURL string +} + +var ( + loginRetryStatuses = slices.Concat(lakectlDefaultRetryStatuses, + []int{http.StatusNotFound}, + ) +) + +func loginRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { + return CheckRetry(ctx, resp, err, loginRetryStatuses) +} + +var loginCmd = &cobra.Command{ + Use: "login", + Short: "Use a web browser to log into lakeFS", + Long: "Connect to lakeFS using a web browser.", + Example: "lakectl login", + Run: func(cmd *cobra.Command, _ []string) { + serverURL, err := url.Parse(cfg.Server.EndpointURL.String()) + if err != nil { + DieErr(fmt.Errorf("get server URL %s: %w", cfg.Server.EndpointURL, err)) + } + + httpClient := getHTTPClientWithRetryConfig(loginRetryPolicy, cfg.Server.LoginRetries) + client := getClient(apigen.WithHTTPClient(httpClient)) + tokenRedirect, err := client.GetTokenRedirectWithResponse(cmd.Context()) + // TODO(ariels): Change back to http.StatusSeeOther after fixing lakeFS server! + DieOnErrorOrUnexpectedStatusCode(tokenRedirect, err, http.StatusOK) + header := tokenRedirect.HTTPResponse.Header + relativeLocation, err := url.Parse(header.Get("location")) + if err != nil { + DieErr(fmt.Errorf("parse relative redirect URL %s: %w", header.Get("location"), err)) + } + mailbox := header.Get(httputil.LoginMailboxHeaderName) + + redirectURL := serverURL.ResolveReference(relativeLocation) + + Write(webLoginTemplate, webLoginParams{RedirectURL: redirectURL.String()}) + err = open.Run(redirectURL.String()) + if err != nil { + Warning(fmt.Sprintf("Failed to open URL: %s", err.Error())) + // Keep going, user can manually use the URL. + } + + // client will retry; use this to wait for login. + // + // TODO(ariels): The timeouts on some lakectl configurations may be too low for + // convenient login. Consider using a RetryClient based on a different + // configuration here.. + resp, err := client.GetTokenFromMailboxWithResponse(cmd.Context(), mailbox) + + DieOnErrorOrUnexpectedStatusCode(resp, err, http.StatusOK) + + loginToken := resp.JSON200 + if loginToken == nil { + Die("No login token", 1) + } + + cache := getTokenCacheOnce() + err = cache.SaveToken(loginToken) + if err != nil { + DieErr(fmt.Errorf("save login token: %w", err)) + } + + Write(loggedInTemplate, struct{ Time string }{Time: time.Now().Format(time.DateTime)}) + }, +} + +//nolint:gochecknoinits +func init() { + rootCmd.AddCommand(loginCmd) +} diff --git a/cmd/lakectl/cmd/retry_client.go b/cmd/lakectl/cmd/retry_client.go index f10412ee9ff..aa651e9227c 100644 --- a/cmd/lakectl/cmd/retry_client.go +++ b/cmd/lakectl/cmd/retry_client.go @@ -7,6 +7,7 @@ import ( "net/http" "net/url" "regexp" + "slices" "github.com/hashicorp/go-retryablehttp" ) @@ -18,7 +19,7 @@ var ( notTrustedErrorRe = regexp.MustCompile(`certificate is not trusted`) ) -func NewRetryClient(retriesCfg RetriesCfg, transport *http.Transport) *http.Client { +func NewRetryClient(retriesCfg RetriesCfg, transport *http.Transport, checkRetry func(ctx context.Context, resp *http.Response, err error) (bool, error)) *http.Client { retryClient := retryablehttp.NewClient() if transport != nil { retryClient.HTTPClient.Transport = transport @@ -27,19 +28,29 @@ func NewRetryClient(retriesCfg RetriesCfg, transport *http.Transport) *http.Clie retryClient.RetryMax = int(retriesCfg.MaxAttempts) retryClient.RetryWaitMin = retriesCfg.MinWaitInterval retryClient.RetryWaitMax = retriesCfg.MaxWaitInterval - retryClient.CheckRetry = lakectlRetryPolicy + retryClient.CheckRetry = checkRetry return retryClient.StandardClient() } -// lakectl retry policy - we retry in the following cases: -// HTTP status 429 - too many requests -// HTTP status 500 - internal server error - could be recoverable -// HTTP status 503 - service unavailable -// We retry on all client transport errors except for: -// - too many redirects +// ShouldRetry checks if we should retry on this (HTTP) status. +type ShouldRetryer []int + +func (s ShouldRetryer) Retry(status int) bool { + return slices.Contains(s, status) +} + +// MakeRetryPolicy makes a retry policy. +// +// - It will _never_ retry on these unrecoverable errors: +// +// - a context error (typically canceled or deadline exceeded); // - invalid http scheme/protocol -// - TLS cert verification failure -func lakectlRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { +// - TLS cert validation failure +// +// - Any other error is retriable. +// +// - When there is no error, it will retry if should says to retry this status. +func CheckRetry(ctx context.Context, resp *http.Response, err error, should ShouldRetryer) (bool, error) { // do not retry on context.Canceled or context.DeadlineExceeded if ctx.Err() != nil { return false, ctx.Err() @@ -58,16 +69,29 @@ func lakectlRetryPolicy(ctx context.Context, resp *http.Response, err error) (bo return false, errors.Unwrap(v) } } - // The stblib http.Client wraps the above errors in a url.Error + // The standard http.Client wraps the above errors in a url.Error // They aren't retryable. Other errors are retryable. return true, nil } // handle HTTP response status code - if resp.StatusCode == http.StatusTooManyRequests || - resp.StatusCode == http.StatusInternalServerError || - resp.StatusCode == http.StatusServiceUnavailable { - return true, nil - } - return false, nil + return should.Retry(resp.StatusCode), nil +} + +// lakectl retry policy - we retry in the following cases: +// HTTP status 429 - too many requests +// HTTP status 500 - internal server error - could be recoverable +// HTTP status 503 - service unavailable +// We retry on all client transport errors except for: +// - too many redirects +// - invalid http scheme/protocol +// - TLS cert verification failure +func lakectlRetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, error) { + return CheckRetry(ctx, resp, err, lakectlDefaultRetryStatuses) +} + +var lakectlDefaultRetryStatuses = ShouldRetryer{ + http.StatusTooManyRequests, + http.StatusInternalServerError, + http.StatusServiceUnavailable, } diff --git a/cmd/lakectl/cmd/root.go b/cmd/lakectl/cmd/root.go index 0605e7db9d6..8b4eca83d4d 100644 --- a/cmd/lakectl/cmd/root.go +++ b/cmd/lakectl/cmd/root.go @@ -26,6 +26,7 @@ import ( "github.com/treeverse/lakefs/pkg/api/apigen" "github.com/treeverse/lakefs/pkg/api/apiutil" "github.com/treeverse/lakefs/pkg/authentication/externalidp/awsiam" + "github.com/treeverse/lakefs/pkg/authentication/internalidp" lakefsconfig "github.com/treeverse/lakefs/pkg/config" "github.com/treeverse/lakefs/pkg/git" giterror "github.com/treeverse/lakefs/pkg/git/errors" @@ -91,8 +92,9 @@ type Configuration struct { } `mapstructure:"http2"` } `mapstructure:"network"` Server struct { - EndpointURL lakefsconfig.OnlyString `mapstructure:"endpoint_url"` - Retries RetriesCfg `mapstructure:"retries"` + EndpointURL lakefsconfig.OnlyString `mapstructure:"endpoint_url"` + Retries RetriesCfg `mapstructure:"retries"` + LoginRetries RetriesCfg `mapstructure:"login_retries"` } `mapstructure:"server"` Options struct { Parallelism int `mapstructure:"parallelism"` @@ -181,6 +183,10 @@ const ( defaultMaxAttempts = 4 defaultMaxRetryInterval = 30 * time.Second defaultMinRetryInterval = 200 * time.Millisecond + + defaultBrowserLoginMaxAttempts = 75 + defaultBrowserLoginMaxRetryInterval = 1 * time.Second + defaultBrowserLoginMinRetryInterval = 50 * time.Millisecond ) const ( @@ -556,7 +562,11 @@ func sendStats(cmd *cobra.Command, cmdSuffix string) { } } -func getHTTPClient() *http.Client { +func getHTTPClient(checkRetry func(ctx context.Context, resp *http.Response, err error) (bool, error)) *http.Client { + return getHTTPClientWithRetryConfig(checkRetry, cfg.Server.Retries) +} + +func getHTTPClientWithRetryConfig(checkRetry func(ctx context.Context, resp *http.Response, err error) (bool, error), retriesCfg RetriesCfg) *http.Client { // Override MaxIdleConnsPerHost to allow highly concurrent access to our API client. // This is done to avoid accumulating many sockets in `TIME_WAIT` status that were closed // only to be immediately reopened. @@ -567,10 +577,10 @@ func getHTTPClient() *http.Client { transport.TLSClientConfig.NextProtos = []string{} } transport.MaxIdleConnsPerHost = DefaultMaxIdleConnsPerHost - if !cfg.Server.Retries.Enabled { + if !retriesCfg.Enabled { return &http.Client{Transport: transport} } - return NewRetryClient(cfg.Server.Retries, transport) + return NewRetryClient(retriesCfg, transport, checkRetry) } func newAWSIAMAuthProviderConfig() (*awsiam.IAMAuthParams, error) { @@ -609,9 +619,8 @@ func newAWSIAMAuthProviderConfig() (*awsiam.IAMAuthParams, error) { return awsiam.NewIAMAuthParams(host, opts...), nil } -func getClient() *apigen.ClientWithResponses { - opts := []apigen.ClientOption{} - httpClient := getHTTPClient() +func getClient(opts ...apigen.ClientOption) *apigen.ClientWithResponses { + httpClient := getHTTPClient(lakectlRetryPolicy) accessKeyID := cfg.Credentials.AccessKeyID secretAccessKey := cfg.Credentials.SecretAccessKey basicAuthProvider, err := securityprovider.NewSecurityProviderBasicAuth(string(accessKeyID), string(secretAccessKey)) @@ -627,9 +636,9 @@ func getClient() *apigen.ClientWithResponses { DieErr(err) } - useIAMAuth := awsIAMparams != nil && accessKeyID == "" && secretAccessKey == "" - if useIAMAuth { - opts = getClientOptions(awsIAMparams, serverEndpoint) + useJWTAuth := accessKeyID == "" && secretAccessKey == "" + if useJWTAuth { + opts = append(getClientOptions(awsIAMparams, serverEndpoint), opts...) } oss := osinfo.GetOSInfo() @@ -664,6 +673,17 @@ func CreateTokenCacheCallback() awsiam.TokenCacheCallback { func getClientOptions(awsIAMparams *awsiam.IAMAuthParams, serverEndpoint string) []apigen.ClientOption { token := getTokenOnce() + logger := logging.ContextUnavailable().WithField("component", "client_auth") + + if awsIAMparams == nil { + if token == nil { + return nil + } + return []apigen.ClientOption{ + internalidp.WithLoginTokenAuth(logger, internalidp.NewFixedLoginClient(token.Token)), + } + } + tokenCacheCallback := CreateTokenCacheCallback() awsLogSigning := cfg.Credentials.Provider.AWSIAM.ClientLogPreSigningRequest @@ -683,7 +703,7 @@ func getClientOptions(awsIAMparams *awsiam.IAMAuthParams, serverEndpoint string) awsAuthProvider := awsiam.WithAWSIAMRoleAuthProviderOption( awsIAMparams, - logging.ContextUnavailable(), + logger, loginClient, token, tokenCacheCallback, @@ -904,11 +924,15 @@ func initConfig() { // set defaults viper.SetDefault("server.endpoint_url", "http://127.0.0.1:8000") + viper.SetDefault("network.http2.enabled", defaultHTTP2Enabled) viper.SetDefault("server.retries.enabled", true) viper.SetDefault("server.retries.max_attempts", defaultMaxAttempts) - viper.SetDefault("network.http2.enabled", defaultHTTP2Enabled) viper.SetDefault("server.retries.max_wait_interval", defaultMaxRetryInterval) viper.SetDefault("server.retries.min_wait_interval", defaultMinRetryInterval) + viper.SetDefault("server.login_retries.enabled", true) + viper.SetDefault("server.login_retries.max_attempts", defaultBrowserLoginMaxAttempts) + viper.SetDefault("server.login_retries.max_wait_interval", defaultBrowserLoginMaxRetryInterval) + viper.SetDefault("server.login_retries.min_wait_interval", defaultBrowserLoginMinRetryInterval) viper.SetDefault("experimental.local.posix_permissions.enabled", false) viper.SetDefault("local.skip_non_regular_files", false) viper.SetDefault("local.symlink_support", false) diff --git a/cmd/lakefs/cmd/run.go b/cmd/lakefs/cmd/run.go index 9b17bff72d7..6480534d162 100644 --- a/cmd/lakefs/cmd/run.go +++ b/cmd/lakefs/cmd/run.go @@ -134,6 +134,11 @@ var runCmd = &cobra.Command{ logger.WithError(err).Fatal("failed to create authentication service") } + loginTokenProvider, err := authenticationfactory.NewLoginTokenProvider(ctx, cfg, logger, kvStore) + if err != nil { + logger.WithError(err).Fatal("failed to create login token provider") + } + blockstoreType := baseCfg.Blockstore.Type if blockstoreType == "mem" { printLocalWarning(os.Stderr, fmt.Sprintf("blockstore type %s", blockstoreType)) @@ -253,6 +258,7 @@ var runCmd = &cobra.Command{ usageReporter, licenseManager, icebergSyncer, + loginTokenProvider, ) // init gateway server diff --git a/docs/src/reference/cli.md b/docs/src/reference/cli.md index c9d9bba18c0..991f0240893 100644 --- a/docs/src/reference/cli.md +++ b/docs/src/reference/cli.md @@ -2204,6 +2204,32 @@ lakectl log --dot lakefs://example-repository/main | dot -Tsvg > graph.svg +### lakectl login + +Use a web browser to log into lakeFS + +

Synopsis

+ +Connect to lakeFS using a web browser. + +``` +lakectl login [flags] +``` + +

Examples

+ +``` +lakectl login +``` + +

Options

+ +``` + -h, --help help for login +``` + + + ### lakectl merge Merge & commit changes from source branch into destination branch diff --git a/esti/golden/lakectl_help.golden b/esti/golden/lakectl_help.golden index 8cd9db7ef51..8236da766a8 100644 --- a/esti/golden/lakectl_help.golden +++ b/esti/golden/lakectl_help.golden @@ -25,6 +25,7 @@ Available Commands: import Import data from external source to a destination branch local Sync local directories with lakeFS paths log Show log of commits + login Use a web browser to log into lakeFS merge Merge & commit changes from source branch into destination branch plugin Manage lakectl plugins repo Manage and explore repos diff --git a/go.mod b/go.mod index 5056325bd9c..f9524c6e548 100644 --- a/go.mod +++ b/go.mod @@ -24,7 +24,7 @@ require ( github.com/jamiealquiza/tachymeter v2.0.0+incompatible github.com/jedib0t/go-pretty/v6 v6.6.7 github.com/manifoldco/promptui v0.9.0 - github.com/matoous/go-nanoid/v2 v2.0.0 + github.com/matoous/go-nanoid/v2 v2.1.0 github.com/minio/minio-go/v7 v7.0.63 github.com/mitchellh/go-homedir v1.1.0 github.com/ory/dockertest/v3 v3.12.0 @@ -138,8 +138,9 @@ require ( github.com/barweiss/go-tuple v1.1.2 // indirect github.com/benbjohnson/clock v1.3.0 // indirect github.com/cncf/xds/go v0.0.0-20250121191232-2f005788dc42 // indirect - github.com/deckarep/golang-set/v2 v2.6.0 // indirect + github.com/deckarep/golang-set/v2 v2.8.0 // indirect github.com/dgraph-io/ristretto/v2 v2.2.0 // indirect + github.com/elnormous/contenttype v1.0.4 // indirect github.com/envoyproxy/go-control-plane/envoy v1.32.4 // indirect github.com/envoyproxy/protoc-gen-validate v1.2.1 // indirect github.com/felixge/httpsnoop v1.0.4 // indirect @@ -185,6 +186,7 @@ require ( github.com/sagikazarmark/locafero v0.7.0 // indirect github.com/samber/mo v1.11.0 // indirect github.com/shopspring/decimal v1.3.1 // indirect + github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 // indirect github.com/sourcegraph/conc v0.3.0 // indirect github.com/spiffe/go-spiffe/v2 v2.5.0 // indirect github.com/ulule/deepcopier v0.0.0-20200430083143-45decc6639b6 // indirect diff --git a/go.sum b/go.sum index 6476fc69aa2..b255b758b24 100644 --- a/go.sum +++ b/go.sum @@ -376,8 +376,8 @@ github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/deckarep/golang-set/v2 v2.6.0 h1:XfcQbWM1LlMB8BsJ8N9vW5ehnnPVIw0je80NsVHagjM= -github.com/deckarep/golang-set/v2 v2.6.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= +github.com/deckarep/golang-set/v2 v2.8.0 h1:swm0rlPCmdWn9mESxKOjWk8hXSqoxOp+ZlfuyaAdFlQ= +github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/deepmap/oapi-codegen v1.5.6 h1:hlUtA13SL2HNoC/5vXDFdGm2AaN1j9/rUu7zedjBiqg= github.com/deepmap/oapi-codegen v1.5.6/go.mod h1:NoliSkZp7cRAkisw65+PUtvgy56f21QQesX1tVUzS8g= github.com/denisenkom/go-mssqldb v0.12.0/go.mod h1:iiK0YP1ZeepvmBQk/QpLEhhTNJgfzrpArPY/aFvc9yU= @@ -408,6 +408,8 @@ github.com/docker/go-units v0.5.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDD github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk= github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= +github.com/elnormous/contenttype v1.0.4 h1:FjmVNkvQOGqSX70yvocph7keC8DtmJaLzTTq6ZOQCI8= +github.com/elnormous/contenttype v1.0.4/go.mod h1:5KTOW8m1kdX1dLMiUJeN9szzR2xkngiv2K+RVZwWBbI= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -800,8 +802,8 @@ github.com/manifoldco/promptui v0.9.0 h1:3V4HzJk1TtXW1MTZMP7mdlwbBpIinw3HztaIlYt github.com/manifoldco/promptui v0.9.0/go.mod h1:ka04sppxSGFAtxX0qhlYQjISsg9mR4GWtQEhdbn6Pgg= github.com/matoous/go-nanoid v1.5.0 h1:VRorl6uCngneC4oUQqOYtO3S0H5QKFtKuKycFG3euek= github.com/matoous/go-nanoid v1.5.0/go.mod h1:zyD2a71IubI24efhpvkJz+ZwfwagzgSO6UNiFsZKN7U= -github.com/matoous/go-nanoid/v2 v2.0.0 h1:d19kur2QuLeHmJBkvYkFdhFBzLoo1XVm2GgTpL+9Tj0= -github.com/matoous/go-nanoid/v2 v2.0.0/go.mod h1:FtS4aGPVfEkxKxhdWPAspZpZSh1cOjtM7Ej/So3hR0g= +github.com/matoous/go-nanoid/v2 v2.1.0 h1:P64+dmq21hhWdtvZfEAofnvJULaRR1Yib0+PnU669bE= +github.com/matoous/go-nanoid/v2 v2.1.0/go.mod h1:KlbGNQ+FhrUNIHUxZdL63t7tl4LaPkZNpUULS8H4uVM= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd/go.mod h1:9ELz6aaclSIGnZBoaSLZ3NAl1VTufbOrXBPvtcy6WiQ= github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= @@ -962,6 +964,8 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966 h1:JIAuq3EEf9cgbU6AtGPK4CTG3Zf6CKMNqf0MHTggAUA= +github.com/skratchdot/open-golang v0.0.0-20200116055534-eef842397966/go.mod h1:sUM3LWHvSMaG192sy56D9F7CNvL7jUJVXoqM1QKLnog= github.com/sourcegraph/conc v0.3.0 h1:OQTbbt6P72L20UqAkXXuLOj79LfEanQ+YQFNpLA9ySo= github.com/sourcegraph/conc v0.3.0/go.mod h1:Sdozi7LEKbFPqYX2/J+iBAM6HpqSLTASQIKqDmF7Mt0= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= diff --git a/go.work.sum b/go.work.sum index c0f4411eb6a..b9c3a91a5b7 100644 --- a/go.work.sum +++ b/go.work.sum @@ -599,6 +599,7 @@ github.com/cyphar/filepath-securejoin v0.2.4 h1:Ugdm7cg7i6ZK6x3xDF1oEu1nfkyfH53E github.com/cyphar/filepath-securejoin v0.2.4/go.mod h1:aPGpWjXOXUn2NCNjFvBE6aRxGGx79pTxQpKOJNYHHl4= github.com/cyphar/filepath-securejoin v0.4.1 h1:JyxxyPEaktOD+GAnqIqTf9A8tHyAG22rowi7HkoSU1s= github.com/cyphar/filepath-securejoin v0.4.1/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= +github.com/deckarep/golang-set/v2 v2.8.0/go.mod h1:VAky9rY/yGXJOLEDv3OMci+7wtDpOF4IN+y82NBOac4= github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA= github.com/devigned/tab v0.1.1 h1:3mD6Kb1mUOYeLpJvTVSDwSg5ZsfSxfvxGRTxRsJsITA= github.com/dgraph-io/badger v1.6.0 h1:DshxFxZWXUcO0xX476VJC07Xsr6ZCBVRHKZ93Oh7Evo= @@ -796,6 +797,7 @@ github.com/mailgun/raymond/v2 v2.0.46 h1:aOYHhvTpF5USySJ0o7cpPno/Uh2I5qg2115K25A github.com/mailgun/raymond/v2 v2.0.46/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= github.com/mailgun/raymond/v2 v2.0.48 h1:5dmlB680ZkFG2RN/0lvTAghrSxIESeu9/2aeDqACtjw= github.com/mailgun/raymond/v2 v2.0.48/go.mod h1:lsgvL50kgt1ylcFJYZiULi5fjPBkkhNfj4KA0W54Z18= +github.com/matoous/go-nanoid/v2 v2.1.0/go.mod h1:KlbGNQ+FhrUNIHUxZdL63t7tl4LaPkZNpUULS8H4uVM= github.com/matryer/moq v0.0.0-20190312154309-6cfb0558e1bd h1:HvFwW+cm9bCbZ/+vuGNq7CRWXql8c0y8nGeYpqmpvmk= github.com/mattn/go-ieproxy v0.0.1 h1:qiyop7gCflfhwCzGyeT0gro3sF9AIg9HU98JORTkqfI= github.com/mattn/goveralls v0.0.2 h1:7eJB6EqsPhRVxvwEXGnqdO2sJI0PTsrWoTMXEk9/OQc= diff --git a/modules/authentication/factory/login_token.go b/modules/authentication/factory/login_token.go new file mode 100644 index 00000000000..40c0dcffbba --- /dev/null +++ b/modules/authentication/factory/login_token.go @@ -0,0 +1,29 @@ +package factory + +import ( + "context" + "time" + + "github.com/treeverse/lakefs/pkg/authentication" + "github.com/treeverse/lakefs/pkg/config" + "github.com/treeverse/lakefs/pkg/kv" + "github.com/treeverse/lakefs/pkg/logging" +) + +type UnimplementedLoginTokenProvider struct{} + +func (l UnimplementedLoginTokenProvider) GetRedirect(ctx context.Context) (*authentication.TokenRedirect, error) { + return nil, authentication.ErrNotImplemented +} + +func (l UnimplementedLoginTokenProvider) Release(ctx context.Context, loginRequestToken string) error { + return authentication.ErrNotImplemented +} + +func (l UnimplementedLoginTokenProvider) GetToken(ctx context.Context, mailbox string) (string, time.Time, error) { + return "", time.Time{}, authentication.ErrNotImplemented +} + +func NewLoginTokenProvider(_ context.Context, c config.Config, logger logging.Logger, store kv.Store) (authentication.LoginTokenProvider, error) { + return UnimplementedLoginTokenProvider{}, nil +} diff --git a/pkg/api/controller.go b/pkg/api/controller.go index f420edae7cc..e6a979bf443 100644 --- a/pkg/api/controller.go +++ b/pkg/api/controller.go @@ -7,6 +7,7 @@ import ( "encoding/json" "errors" "fmt" + "html/template" "io" "mime" "mime/multipart" @@ -22,6 +23,7 @@ import ( "github.com/aws/aws-sdk-go-v2/feature/s3/manager" "github.com/davecgh/go-spew/spew" + "github.com/elnormous/contenttype" "github.com/go-openapi/swag" "github.com/gorilla/sessions" authacl "github.com/treeverse/lakefs/contrib/auth/acl" @@ -90,23 +92,24 @@ type Migrator interface { } type Controller struct { - Config config.Config - Catalog *catalog.Catalog - Authenticator auth.Authenticator - Auth auth.Service - Authentication authentication.Service - BlockAdapter block.Adapter - MetadataManager auth.MetadataManager - Migrator Migrator - Collector stats.Collector - Actions actionsHandler - AuditChecker AuditChecker - Logger logging.Logger - sessionStore sessions.Store - PathProvider upload.PathProvider - usageReporter stats.UsageReporterOperations - licenseManager license.Manager - icebergSyncer icebergsync.Controller + Config config.Config + Catalog *catalog.Catalog + Authenticator auth.Authenticator + Auth auth.Service + Authentication authentication.Service + BlockAdapter block.Adapter + MetadataManager auth.MetadataManager + Migrator Migrator + Collector stats.Collector + Actions actionsHandler + AuditChecker AuditChecker + Logger logging.Logger + sessionStore sessions.Store + PathProvider upload.PathProvider + usageReporter stats.UsageReporterOperations + licenseManager license.Manager + icebergSyncer icebergsync.Controller + loginTokenProvider authentication.LoginTokenProvider } var usageCounter = stats.NewUsageCounter() @@ -129,25 +132,27 @@ func NewController( usageReporter stats.UsageReporterOperations, licenseManager license.Manager, icebergSyncer icebergsync.Controller, + loginTokenProvider authentication.LoginTokenProvider, ) *Controller { return &Controller{ - Config: cfg, - Catalog: catalog, - Authenticator: authenticator, - Auth: authService, - Authentication: authenticationService, - BlockAdapter: blockAdapter, - MetadataManager: metadataManager, - Migrator: migrator, - Collector: collector, - Actions: actions, - AuditChecker: auditChecker, - Logger: logger, - sessionStore: sessionStore, - PathProvider: pathProvider, - usageReporter: usageReporter, - licenseManager: licenseManager, - icebergSyncer: icebergSyncer, + Config: cfg, + Catalog: catalog, + Authenticator: authenticator, + Auth: authService, + Authentication: authenticationService, + BlockAdapter: blockAdapter, + MetadataManager: metadataManager, + Migrator: migrator, + Collector: collector, + Actions: actions, + AuditChecker: auditChecker, + Logger: logger, + sessionStore: sessionStore, + PathProvider: pathProvider, + usageReporter: usageReporter, + licenseManager: licenseManager, + icebergSyncer: icebergSyncer, + loginTokenProvider: loginTokenProvider, } } @@ -870,6 +875,130 @@ func (c *Controller) StsLogin(w http.ResponseWriter, r *http.Request, body apige writeResponse(w, r, http.StatusOK, responseToken) } +func (c *Controller) GetTokenRedirect(w http.ResponseWriter, r *http.Request) { + ctx := r.Context() + // Login method needs no auth! + redirect, err := c.loginTokenProvider.GetRedirect(ctx) + if c.handleAPIError(ctx, w, r, err) { + return + } + + w.Header().Set("Location", redirect.RedirectURL) + w.Header().Set(httputil.LoginMailboxHeaderName, redirect.Mailbox) + + writeResponse(w, r, http.StatusOK, nil) +} + +func (c *Controller) GetTokenFromMailbox(w http.ResponseWriter, r *http.Request, mailbox string) { + ctx := r.Context() + // Login method needs no auth! + token, expiresAt, err := c.loginTokenProvider.GetToken(ctx, mailbox) + if c.handleAPIError(ctx, w, r, err) { + return + } + + // This call is repeated, so only log after we've found the token is valid. + c.LogAction(ctx, "get_token_from_mailbox", r, "", "", "") + + c.Logger. + WithContext(r.Context()). + WithFields(logging.Fields{ + "mailbox": mailbox, + "token_expiration": expiresAt, + }). + Debug("Got login token") + + response := apigen.AuthenticationToken{ + Token: token, + TokenExpiration: swag.Int64(expiresAt.Unix()), + } + writeResponse(w, r, http.StatusOK, response) +} + +var releasedTokenTemplate = template.Must( + template.New("released-token"). + Parse(`{{define "releasedToken" -}} + + + Logged in + +
You are logged in as {{.Username}}. It is safe to close this window.
+ + +{{- end}}`)) + +type UserData struct { + Username string +} + +var ( + textHTML = contenttype.MediaType{Type: "text", Subtype: "html"} + releaseTokenAcceptableMediaTypes = []contenttype.MediaType{ + textHTML, + {Type: "*", Subtype: "*"}, + } +) + +func (c *Controller) ReleaseTokenToMailbox(w http.ResponseWriter, r *http.Request, loginRequestToken string) { + ctx := r.Context() + + c.LogAction(ctx, "release_token_to_mailbox", r, "", "", "") + + user, err := auth.GetUser(ctx) + if err != nil { + // This is typically called from a browser - send it to login, return here + // after. + c.Logger. + WithContext(ctx). + WithError(err). + WithField("accept", r.Header.Get("Accept")). + Debug("Failed to get user - redirect to login") + + redirectURL, err := url.Parse(c.Config.AuthConfig().GetLoginURL()) + if c.handleAPIError(ctx, w, r, err) { + return + } + q := redirectURL.Query() + q.Set("next", r.URL.String()) // Encode query-escapes this string. + redirectURL.RawQuery = q.Encode() + w.Header().Set("Location", redirectURL.String()) + w.WriteHeader(http.StatusTemporaryRedirect) + return + } + + // Release will release a token for the authenticated user. + err = c.loginTokenProvider.Release(ctx, loginRequestToken) + if c.handleAPIError(ctx, w, r, err) { + return + } + + mediaType, _, err := contenttype.GetAcceptableMediaType(r, releaseTokenAcceptableMediaTypes) + if err != nil { + c.Logger. + WithContext(r.Context()). + WithError(err). + WithField("accept", r.Header.Get("Accept")). + Warn("Failed to parse Content-Type - no user-friendly page") + // Keep going - errors are safe here, at worst the user will not get a pretty page. + } + + switch { + case mediaType.EqualsMIME(textHTML): + username := user.Username + // This endpoint is _usually_ visited by a browser. Report to the user that + // they logged in, telling them the name they used to log in. + httputil.KeepPrivate(w) + w.WriteHeader(http.StatusOK) + + err = releasedTokenTemplate.ExecuteTemplate(w, "releasedToken", &UserData{Username: username}) + if c.handleAPIError(ctx, w, r, err) { + return + } + default: + writeResponse(w, r, http.StatusNoContent, nil) + } +} + func (c *Controller) GetPhysicalAddress(w http.ResponseWriter, r *http.Request, repository, branch string, params apigen.GetPhysicalAddressParams) { if !c.authorize(w, r, permissions.Node{ Permission: permissions.Permission{ @@ -4927,11 +5056,7 @@ func (c *Controller) GetObject(w http.ResponseWriter, r *http.Request, repositor w.Header().Set("Last-Modified", lastModified) w.Header().Set("Content-Type", entry.ContentType) // for security, make sure the browser and any proxies en route don't cache the response - w.Header().Set("Cache-Control", "no-store, must-revalidate") - w.Header().Set("Expires", "0") - w.Header().Set("X-Content-Type-Options", "nosniff") - w.Header().Set("X-Frame-Options", "SAMEORIGIN") - w.Header().Set("Content-Security-Policy", "default-src 'none'") + httputil.KeepPrivate(w) w.Header().Set("Content-Disposition", "attachment") // handle partial response if byte range supplied @@ -6191,8 +6316,8 @@ func (c *Controller) GetUsageReportSummary(w http.ResponseWriter, r *http.Reques // base on content-type return plain text or json (default) if r.Header.Get("Accept") == "text/plain" { + httputil.KeepPrivate(w) w.Header().Set("Content-Type", "text/plain; charset=utf-8") - w.Header().Set("X-Content-Type-Options", "nosniff") _, _ = fmt.Fprintf(w, "Usage for installation ID: %s\n", installationID) for _, rec := range records { _, _ = fmt.Fprintf(w, "%d-%02d: %12d\n", rec.Year, rec.Month, rec.Count) diff --git a/pkg/api/serve.go b/pkg/api/serve.go index fd1eb316a86..b91b584d033 100644 --- a/pkg/api/serve.go +++ b/pkg/api/serve.go @@ -53,6 +53,7 @@ func Serve( usageReporter stats.UsageReporterOperations, licenseManager license.Manager, icebergSyncer icebergsync.Controller, + loginTokenProvider authentication.LoginTokenProvider, ) *chi.Mux { logger.Info("initialize OpenAPI server") swagger, err := apigen.GetSwagger() @@ -94,6 +95,7 @@ func Serve( usageReporter, licenseManager, icebergSyncer, + loginTokenProvider, ) apigen.HandlerFromMuxWithBaseURL(controller, apiRouter, apiutil.BaseURL) diff --git a/pkg/api/serve_test.go b/pkg/api/serve_test.go index 8b9f9838ba6..a02161b2b4c 100644 --- a/pkg/api/serve_test.go +++ b/pkg/api/serve_test.go @@ -14,6 +14,7 @@ import ( "github.com/deepmap/oapi-codegen/pkg/securityprovider" "github.com/spf13/viper" apifactory "github.com/treeverse/lakefs/modules/api/factory" + authenticationfactory "github.com/treeverse/lakefs/modules/authentication/factory" configfactory "github.com/treeverse/lakefs/modules/config/factory" licensefactory "github.com/treeverse/lakefs/modules/license/factory" "github.com/treeverse/lakefs/pkg/actions" @@ -168,8 +169,10 @@ func setupHandler(t testing.TB) (http.Handler, *dependencies) { authenticationService := authentication.NewDummyService() licenseManager, _ := licensefactory.NewLicenseManager(ctx, cfg) + logger := logging.FromContext(ctx) + loginTokenProvider, err := authenticationfactory.NewLoginTokenProvider(ctx, cfg, logger, kvStore) + testutil.Must(t, err) icebergSyncer := apifactory.NewIcebergSyncController(cfg) - logger := logging.ContextUnavailable() handler := api.Serve( cfg, c, @@ -189,6 +192,7 @@ func setupHandler(t testing.TB) (http.Handler, *dependencies) { stats.DefaultUsageReporter, licenseManager, icebergSyncer, + loginTokenProvider, ) // reset cloud metadata - faster setup, the cloud metadata maintain its own tests diff --git a/pkg/authentication/internalidp/jwt_auth.go b/pkg/authentication/internalidp/jwt_auth.go new file mode 100644 index 00000000000..a615cf601e5 --- /dev/null +++ b/pkg/authentication/internalidp/jwt_auth.go @@ -0,0 +1,53 @@ +package internalidp + +import ( + "context" + "fmt" + "net/http" + + "github.com/treeverse/lakefs/pkg/api/apigen" + "github.com/treeverse/lakefs/pkg/logging" +) + +type JWTAuthClient struct { + Client *apigen.ClientWithResponses +} + +// LoginClient has all the methods used during a token-based login. +type LoginClient interface { + // GetToken returns a valid token, refreshing it if needed. + GetToken(ctx context.Context) (string, error) +} + +// FixedLoginClient just returns the same token each time, which it does not refresh. +type FixedLoginClient struct { + token string +} + +func NewFixedLoginClient(token string) *FixedLoginClient { + return &FixedLoginClient{token} +} + +func (c *FixedLoginClient) GetToken(_ context.Context) (string, error) { + return c.token, nil +} + +// WithLoginTokenAuth adds an authentication provider into the GetClient request, which authenticates +// using the JWT token. It can update its token. +// +// BUG(ariels): It does not (yet) update its token. +func WithLoginTokenAuth(logger logging.Logger, client LoginClient) apigen.ClientOption { + intercept := NewJWTClientInterceptor(logger, client) + return apigen.WithRequestEditorFn(intercept) +} + +func NewJWTClientInterceptor(logger logging.Logger, client LoginClient) apigen.RequestEditorFn { + return func(ctx context.Context, req *http.Request) error { + token, err := client.GetToken(ctx) + if err != nil { + return err + } + req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + return nil + } +} diff --git a/pkg/authentication/tokens.go b/pkg/authentication/tokens.go new file mode 100644 index 00000000000..a434431ae7f --- /dev/null +++ b/pkg/authentication/tokens.go @@ -0,0 +1,23 @@ +package authentication + +import ( + "context" + "time" +) + +type TokenRedirect struct { + RedirectURL string + Mailbox string +} + +type LoginTokenProvider interface { + // GetRedirect is called to start logging in via an authenticated user. It is called + // unauthenticated, initiated by the requesting client, with no user on the context. + GetRedirect(ctx context.Context) (*TokenRedirect, error) + // Release drops token into mailbox, releasing it for the next GetToken call. It is + // called authenticated, initiated by the web browser running. + Release(ctx context.Context, loginRequestToken string) error + // GetToken returns a token waiting on mailbox. It is called unauthenticated, initiated + // the requesting client, with no user on the context. + GetToken(ctx context.Context, mailbox string) (string, time.Time, error) +} diff --git a/pkg/config/config.go b/pkg/config/config.go index 67f8437ba2f..60762de358a 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -441,6 +441,7 @@ type AuthConfig interface { // UseUILoginPlaceholders Added this function to the interface because its implementation requires parameters from both BaseAuth and // AuthUIConfig, so neither struct alone could implement it. UseUILoginPlaceholders() bool + GetLoginURL() string } type UIConfig interface { @@ -791,6 +792,13 @@ func (b *BaseAuth) IsExternalPrincipalsEnabled() bool { return b.AuthenticationAPI.ExternalPrincipalsEnabled } +func (u *AuthUIConfig) GetLoginURL() string { + if u.LoginURL != "" { + return u.LoginURL + } + return "/auth/login" +} + func (u *AuthUIConfig) IsAuthBasic() bool { return u.RBAC == AuthRBACNone } diff --git a/pkg/httputil/headers.go b/pkg/httputil/headers.go index 91bd41e8a23..f6018a1837f 100644 --- a/pkg/httputil/headers.go +++ b/pkg/httputil/headers.go @@ -1,5 +1,6 @@ package httputil const ( - RequestIDHeaderName = "X-Request-ID" + RequestIDHeaderName = "X-Request-ID" + LoginMailboxHeaderName = "X-LakeFS-Mailbox" ) diff --git a/pkg/httputil/response.go b/pkg/httputil/response.go index 0c89dcebbd8..0088d6d75ec 100644 --- a/pkg/httputil/response.go +++ b/pkg/httputil/response.go @@ -6,3 +6,14 @@ import "net/http" func IsSuccessStatusCode(response *http.Response) bool { return response.StatusCode >= http.StatusOK && response.StatusCode < http.StatusMultipleChoices } + +// KeepPrivate sets some headers on response to keep it private: no caching, no sniff, +// sameorigin, etc. It should be used on any non-API response (HTML, text, object contents, +// etc.) +func KeepPrivate(w http.ResponseWriter) { + w.Header().Set("Cache-Control", "no-store, must-revalidate") + w.Header().Set("Expires", "0") + w.Header().Set("X-Content-Type-Options", "nosniff") + w.Header().Set("X-Frame-Options", "SAMEORIGIN") + w.Header().Set("Content-Security-Policy", "default-src 'none'") +} diff --git a/pkg/loadtest/local_load_test.go b/pkg/loadtest/local_load_test.go index 6eaa8373898..9009b22e668 100644 --- a/pkg/loadtest/local_load_test.go +++ b/pkg/loadtest/local_load_test.go @@ -10,6 +10,7 @@ import ( "github.com/spf13/viper" apifactory "github.com/treeverse/lakefs/modules/api/factory" + authenticationfactory "github.com/treeverse/lakefs/modules/authentication/factory" catalogfactory "github.com/treeverse/lakefs/modules/catalog/factory" configfactory "github.com/treeverse/lakefs/modules/config/factory" licensefactory "github.com/treeverse/lakefs/modules/license/factory" @@ -55,7 +56,8 @@ func TestLocalLoad(t *testing.T) { } kvStore := kvtest.GetStore(ctx, t) - authService := auth.NewBasicAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), authparams.ServiceCache{}, logging.FromContext(ctx)) + logger := logging.FromContext(ctx) + authService := auth.NewBasicAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), authparams.ServiceCache{}, logger) meta := auth.NewKVMetadataManager("local_load_test", baseCfg.Installation.FixedID, baseCfg.Database.Type, kvStore) blockstoreType := os.Getenv(testutil.EnvKeyUseBlockAdapter) @@ -92,6 +94,8 @@ func TestLocalLoad(t *testing.T) { auditChecker := version.NewDefaultAuditChecker(baseCfg.Security.AuditCheckURL, "", nil) authenticationService := authentication.NewDummyService() licenseManager, _ := licensefactory.NewLicenseManager(ctx, cfg) + loginTokenProvider, err := authenticationfactory.NewLoginTokenProvider(ctx, cfg, logger, kvStore) + testutil.Must(t, err) icebergSyncer := apifactory.NewIcebergSyncController(cfg) handler := api.Serve( cfg, @@ -112,6 +116,7 @@ func TestLocalLoad(t *testing.T) { stats.DefaultUsageReporter, licenseManager, icebergSyncer, + loginTokenProvider, ) ts := httptest.NewServer(handler) diff --git a/webui/src/pages/index.jsx b/webui/src/pages/index.jsx index 8122a42e7c8..31183aacb58 100644 --- a/webui/src/pages/index.jsx +++ b/webui/src/pages/index.jsx @@ -1,10 +1,11 @@ -import React from "react"; +import React, { useEffect } from "react"; import { BrowserRouter as Router, Routes, Route, Navigate, + useLocation, } from "react-router-dom"; import {WithLoginConfigContext} from "../lib/hooks/conf"; @@ -48,6 +49,17 @@ import {WithAppContext} from "../lib/hooks/appContext"; import {AuthProvider} from "../lib/auth/authContext"; import RequiresAuth from "../lib/components/requiresAuth"; +// Component to handle browser redirection - to exit the React app. +const Redirect = () => { + const location = useLocation(); + // Break out of React to the actual URL - do not use Navigate. + useEffect(() => { + window.location.replace(location.pathname); + }, [location.pathname]); + + return
Redirecting...
; +}; + export const IndexPage = () => { return ( @@ -115,7 +127,8 @@ export const IndexPage = () => { - }/> + }/> + }/> }> }/>