diff --git a/api/swagger.yml b/api/swagger.yml index 9fdccb8c131..de7e3cc26a4 100644 --- a/api/swagger.yml +++ b/api/swagger.yml @@ -713,8 +713,6 @@ components: id: type: string description: a unique identifier for the user. - invite_user: - type: boolean required: - id @@ -880,14 +878,6 @@ components: items: $ref: "#/components/schemas/Group" - AuthCapabilities: - type: object - properties: - invite_user: - type: boolean - forgot_password: - type: boolean - UserList: type: object required: @@ -1562,25 +1552,6 @@ paths: default: $ref: "#/components/responses/ServerError" - - - /auth/capabilities: - get: - tags: - - internal - operationId: getAuthCapabilities - summary: list authentication capabilities supported - security: [] - responses: - 200: - description: auth capabilities - content: - application/json: - schema: - $ref: "#/components/schemas/AuthCapabilities" - default: - $ref: "#/components/responses/ServerError" - /auth/users: get: tags: diff --git a/clients/java/README.md b/clients/java/README.md index 7d09749cb3f..566a6ab175c 100644 --- a/clients/java/README.md +++ b/clients/java/README.md @@ -192,7 +192,6 @@ Class | Method | HTTP request | Description *ImportApi* | [**importStatus**](docs/ImportApi.md#importStatus) | **GET** /repositories/{repository}/branches/{branch}/import | get import status *ImportApi* | [**ingestRange**](docs/ImportApi.md#ingestRange) | **POST** /repositories/{repository}/branches/ranges | create a lakeFS range file from the source uri *InternalApi* | [**createBranchProtectionRulePreflight**](docs/InternalApi.md#createBranchProtectionRulePreflight) | **GET** /repositories/{repository}/branch_protection/set_allowed | -*InternalApi* | [**getAuthCapabilities**](docs/InternalApi.md#getAuthCapabilities) | **GET** /auth/capabilities | list authentication capabilities supported *InternalApi* | [**getSetupState**](docs/InternalApi.md#getSetupState) | **GET** /setup_lakefs | check if the lakeFS installation is already set up *InternalApi* | [**postStatsEvents**](docs/InternalApi.md#postStatsEvents) | **POST** /statistics | post stats events, this endpoint is meant for internal use only *InternalApi* | [**setGarbageCollectionRulesPreflight**](docs/InternalApi.md#setGarbageCollectionRulesPreflight) | **GET** /repositories/{repository}/gc/rules/set_allowed | @@ -246,7 +245,6 @@ Class | Method | HTTP request | Description - [AccessKeyCredentials](docs/AccessKeyCredentials.md) - [ActionRun](docs/ActionRun.md) - [ActionRunList](docs/ActionRunList.md) - - [AuthCapabilities](docs/AuthCapabilities.md) - [AuthenticationToken](docs/AuthenticationToken.md) - [BranchCreation](docs/BranchCreation.md) - [BranchProtectionRule](docs/BranchProtectionRule.md) diff --git a/clients/java/api/openapi.yaml b/clients/java/api/openapi.yaml index 3761872ef7b..7ef3e36abb9 100644 --- a/clients/java/api/openapi.yaml +++ b/clients/java/api/openapi.yaml @@ -166,27 +166,6 @@ paths: - auth x-contentType: application/json x-accepts: application/json - /auth/capabilities: - get: - operationId: getAuthCapabilities - responses: - "200": - content: - application/json: - schema: - $ref: '#/components/schemas/AuthCapabilities' - description: auth capabilities - default: - content: - application/json: - schema: - $ref: '#/components/schemas/Error' - description: Internal Server Error - security: [] - summary: list authentication capabilities supported - tags: - - internal - x-accepts: application/json /auth/users: get: operationId: listUsers @@ -6398,14 +6377,11 @@ components: type: object UserCreation: example: - invite_user: true id: id properties: id: description: a unique identifier for the user. type: string - invite_user: - type: boolean required: - id type: object @@ -6630,16 +6606,6 @@ components: - pagination - results type: object - AuthCapabilities: - example: - invite_user: true - forgot_password: true - properties: - invite_user: - type: boolean - forgot_password: - type: boolean - type: object UserList: example: pagination: diff --git a/clients/java/docs/AuthCapabilities.md b/clients/java/docs/AuthCapabilities.md deleted file mode 100644 index 664d2ccb8fd..00000000000 --- a/clients/java/docs/AuthCapabilities.md +++ /dev/null @@ -1,14 +0,0 @@ - - -# AuthCapabilities - - -## Properties - -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**inviteUser** | **Boolean** | | [optional] -**forgotPassword** | **Boolean** | | [optional] - - - diff --git a/clients/java/docs/InternalApi.md b/clients/java/docs/InternalApi.md index ba761086508..d6167d9f08e 100644 --- a/clients/java/docs/InternalApi.md +++ b/clients/java/docs/InternalApi.md @@ -5,7 +5,6 @@ All URIs are relative to *http://localhost/api/v1* Method | HTTP request | Description ------------- | ------------- | ------------- [**createBranchProtectionRulePreflight**](InternalApi.md#createBranchProtectionRulePreflight) | **GET** /repositories/{repository}/branch_protection/set_allowed | -[**getAuthCapabilities**](InternalApi.md#getAuthCapabilities) | **GET** /auth/capabilities | list authentication capabilities supported [**getSetupState**](InternalApi.md#getSetupState) | **GET** /setup_lakefs | check if the lakeFS installation is already set up [**postStatsEvents**](InternalApi.md#postStatsEvents) | **POST** /statistics | post stats events, this endpoint is meant for internal use only [**setGarbageCollectionRulesPreflight**](InternalApi.md#setGarbageCollectionRulesPreflight) | **GET** /repositories/{repository}/gc/rules/set_allowed | @@ -106,63 +105,6 @@ null (empty response body) **409** | Resource Conflicts With Target | - | **0** | Internal Server Error | - | - -# **getAuthCapabilities** -> AuthCapabilities getAuthCapabilities() - -list authentication capabilities supported - -### Example -```java -// Import classes: -import io.lakefs.clients.api.ApiClient; -import io.lakefs.clients.api.ApiException; -import io.lakefs.clients.api.Configuration; -import io.lakefs.clients.api.models.*; -import io.lakefs.clients.api.InternalApi; - -public class Example { - public static void main(String[] args) { - ApiClient defaultClient = Configuration.getDefaultApiClient(); - defaultClient.setBasePath("http://localhost/api/v1"); - - InternalApi apiInstance = new InternalApi(defaultClient); - try { - AuthCapabilities result = apiInstance.getAuthCapabilities(); - System.out.println(result); - } catch (ApiException e) { - System.err.println("Exception when calling InternalApi#getAuthCapabilities"); - 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 - -[**AuthCapabilities**](AuthCapabilities.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - -### HTTP response details -| Status code | Description | Response headers | -|-------------|-------------|------------------| -**200** | auth capabilities | - | -**0** | Internal Server Error | - | - # **getSetupState** > SetupState getSetupState() diff --git a/clients/java/docs/UserCreation.md b/clients/java/docs/UserCreation.md index 12d8a5af0a7..57ce45b33de 100644 --- a/clients/java/docs/UserCreation.md +++ b/clients/java/docs/UserCreation.md @@ -8,7 +8,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **String** | a unique identifier for the user. | -**inviteUser** | **Boolean** | | [optional] diff --git a/clients/java/src/main/java/io/lakefs/clients/api/InternalApi.java b/clients/java/src/main/java/io/lakefs/clients/api/InternalApi.java index 1c0fc48eb98..7ad69ca4535 100644 --- a/clients/java/src/main/java/io/lakefs/clients/api/InternalApi.java +++ b/clients/java/src/main/java/io/lakefs/clients/api/InternalApi.java @@ -27,7 +27,6 @@ import java.io.IOException; -import io.lakefs.clients.api.model.AuthCapabilities; import io.lakefs.clients.api.model.CommPrefsInput; import io.lakefs.clients.api.model.CredentialsWithSecret; import io.lakefs.clients.api.model.Error; @@ -185,112 +184,6 @@ public okhttp3.Call createBranchProtectionRulePreflightAsync(String repository, localVarApiClient.executeAsync(localVarCall, _callback); return localVarCall; } - /** - * Build call for getAuthCapabilities - * @param _callback Callback for upload/download progress - * @return Call to execute - * @throws ApiException If fail to serialize the request body object - * @http.response.details - - - - -
Status Code Description Response Headers
200 auth capabilities -
0 Internal Server Error -
- */ - public okhttp3.Call getAuthCapabilitiesCall(final ApiCallback _callback) throws ApiException { - Object localVarPostBody = null; - - // create path and map variables - String localVarPath = "/auth/capabilities"; - - 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); - localVarHeaderParams.put("Content-Type", localVarContentType); - - String[] localVarAuthNames = new String[] { }; - return localVarApiClient.buildCall(localVarPath, "GET", localVarQueryParams, localVarCollectionQueryParams, localVarPostBody, localVarHeaderParams, localVarCookieParams, localVarFormParams, localVarAuthNames, _callback); - } - - @SuppressWarnings("rawtypes") - private okhttp3.Call getAuthCapabilitiesValidateBeforeCall(final ApiCallback _callback) throws ApiException { - - - okhttp3.Call localVarCall = getAuthCapabilitiesCall(_callback); - return localVarCall; - - } - - /** - * list authentication capabilities supported - * - * @return AuthCapabilities - * @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 auth capabilities -
0 Internal Server Error -
- */ - public AuthCapabilities getAuthCapabilities() throws ApiException { - ApiResponse localVarResp = getAuthCapabilitiesWithHttpInfo(); - return localVarResp.getData(); - } - - /** - * list authentication capabilities supported - * - * @return ApiResponse<AuthCapabilities> - * @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 auth capabilities -
0 Internal Server Error -
- */ - public ApiResponse getAuthCapabilitiesWithHttpInfo() throws ApiException { - okhttp3.Call localVarCall = getAuthCapabilitiesValidateBeforeCall(null); - Type localVarReturnType = new TypeToken(){}.getType(); - return localVarApiClient.execute(localVarCall, localVarReturnType); - } - - /** - * list authentication capabilities supported (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 auth capabilities -
0 Internal Server Error -
- */ - public okhttp3.Call getAuthCapabilitiesAsync(final ApiCallback _callback) throws ApiException { - - okhttp3.Call localVarCall = getAuthCapabilitiesValidateBeforeCall(_callback); - Type localVarReturnType = new TypeToken(){}.getType(); - localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); - return localVarCall; - } /** * Build call for getSetupState * @param _callback Callback for upload/download progress diff --git a/clients/java/src/main/java/io/lakefs/clients/api/model/AuthCapabilities.java b/clients/java/src/main/java/io/lakefs/clients/api/model/AuthCapabilities.java deleted file mode 100644 index 0b2632f5bc4..00000000000 --- a/clients/java/src/main/java/io/lakefs/clients/api/model/AuthCapabilities.java +++ /dev/null @@ -1,127 +0,0 @@ -/* - * lakeFS API - * lakeFS HTTP API - * - * The version of the OpenAPI document: 0.1.0 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -package io.lakefs.clients.api.model; - -import java.util.Objects; -import java.util.Arrays; -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; -import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.io.IOException; - -/** - * AuthCapabilities - */ -@javax.annotation.Generated(value = "org.openapitools.codegen.languages.JavaClientCodegen") -public class AuthCapabilities { - public static final String SERIALIZED_NAME_INVITE_USER = "invite_user"; - @SerializedName(SERIALIZED_NAME_INVITE_USER) - private Boolean inviteUser; - - public static final String SERIALIZED_NAME_FORGOT_PASSWORD = "forgot_password"; - @SerializedName(SERIALIZED_NAME_FORGOT_PASSWORD) - private Boolean forgotPassword; - - - public AuthCapabilities inviteUser(Boolean inviteUser) { - - this.inviteUser = inviteUser; - return this; - } - - /** - * Get inviteUser - * @return inviteUser - **/ - @javax.annotation.Nullable - @ApiModelProperty(value = "") - - public Boolean getInviteUser() { - return inviteUser; - } - - - public void setInviteUser(Boolean inviteUser) { - this.inviteUser = inviteUser; - } - - - public AuthCapabilities forgotPassword(Boolean forgotPassword) { - - this.forgotPassword = forgotPassword; - return this; - } - - /** - * Get forgotPassword - * @return forgotPassword - **/ - @javax.annotation.Nullable - @ApiModelProperty(value = "") - - public Boolean getForgotPassword() { - return forgotPassword; - } - - - public void setForgotPassword(Boolean forgotPassword) { - this.forgotPassword = forgotPassword; - } - - - @Override - public boolean equals(Object o) { - if (this == o) { - return true; - } - if (o == null || getClass() != o.getClass()) { - return false; - } - AuthCapabilities authCapabilities = (AuthCapabilities) o; - return Objects.equals(this.inviteUser, authCapabilities.inviteUser) && - Objects.equals(this.forgotPassword, authCapabilities.forgotPassword); - } - - @Override - public int hashCode() { - return Objects.hash(inviteUser, forgotPassword); - } - - @Override - public String toString() { - StringBuilder sb = new StringBuilder(); - sb.append("class AuthCapabilities {\n"); - sb.append(" inviteUser: ").append(toIndentedString(inviteUser)).append("\n"); - sb.append(" forgotPassword: ").append(toIndentedString(forgotPassword)).append("\n"); - sb.append("}"); - return sb.toString(); - } - - /** - * Convert the given object to string with each line indented by 4 spaces - * (except the first line). - */ - private String toIndentedString(Object o) { - if (o == null) { - return "null"; - } - return o.toString().replace("\n", "\n "); - } - -} - diff --git a/clients/java/src/main/java/io/lakefs/clients/api/model/UserCreation.java b/clients/java/src/main/java/io/lakefs/clients/api/model/UserCreation.java index 7af62d415c8..0b29942fdb3 100644 --- a/clients/java/src/main/java/io/lakefs/clients/api/model/UserCreation.java +++ b/clients/java/src/main/java/io/lakefs/clients/api/model/UserCreation.java @@ -33,10 +33,6 @@ public class UserCreation { @SerializedName(SERIALIZED_NAME_ID) private String id; - public static final String SERIALIZED_NAME_INVITE_USER = "invite_user"; - @SerializedName(SERIALIZED_NAME_INVITE_USER) - private Boolean inviteUser; - public UserCreation id(String id) { @@ -61,29 +57,6 @@ public void setId(String id) { } - public UserCreation inviteUser(Boolean inviteUser) { - - this.inviteUser = inviteUser; - return this; - } - - /** - * Get inviteUser - * @return inviteUser - **/ - @javax.annotation.Nullable - @ApiModelProperty(value = "") - - public Boolean getInviteUser() { - return inviteUser; - } - - - public void setInviteUser(Boolean inviteUser) { - this.inviteUser = inviteUser; - } - - @Override public boolean equals(Object o) { if (this == o) { @@ -93,13 +66,12 @@ public boolean equals(Object o) { return false; } UserCreation userCreation = (UserCreation) o; - return Objects.equals(this.id, userCreation.id) && - Objects.equals(this.inviteUser, userCreation.inviteUser); + return Objects.equals(this.id, userCreation.id); } @Override public int hashCode() { - return Objects.hash(id, inviteUser); + return Objects.hash(id); } @Override @@ -107,7 +79,6 @@ public String toString() { StringBuilder sb = new StringBuilder(); sb.append("class UserCreation {\n"); sb.append(" id: ").append(toIndentedString(id)).append("\n"); - sb.append(" inviteUser: ").append(toIndentedString(inviteUser)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/clients/java/src/test/java/io/lakefs/clients/api/InternalApiTest.java b/clients/java/src/test/java/io/lakefs/clients/api/InternalApiTest.java index d27a16781ec..69e649032b8 100644 --- a/clients/java/src/test/java/io/lakefs/clients/api/InternalApiTest.java +++ b/clients/java/src/test/java/io/lakefs/clients/api/InternalApiTest.java @@ -14,7 +14,6 @@ package io.lakefs.clients.api; import io.lakefs.clients.api.ApiException; -import io.lakefs.clients.api.model.AuthCapabilities; import io.lakefs.clients.api.model.CommPrefsInput; import io.lakefs.clients.api.model.CredentialsWithSecret; import io.lakefs.clients.api.model.Error; @@ -54,20 +53,6 @@ public void createBranchProtectionRulePreflightTest() throws ApiException { // TODO: test validations } - /** - * list authentication capabilities supported - * - * - * - * @throws ApiException - * if the Api call fails - */ - @Test - public void getAuthCapabilitiesTest() throws ApiException { - AuthCapabilities response = api.getAuthCapabilities(); - // TODO: test validations - } - /** * check if the lakeFS installation is already set up * diff --git a/clients/java/src/test/java/io/lakefs/clients/api/model/AuthCapabilitiesTest.java b/clients/java/src/test/java/io/lakefs/clients/api/model/AuthCapabilitiesTest.java deleted file mode 100644 index bfb64d272eb..00000000000 --- a/clients/java/src/test/java/io/lakefs/clients/api/model/AuthCapabilitiesTest.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * lakeFS API - * lakeFS HTTP API - * - * The version of the OpenAPI document: 0.1.0 - * - * - * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech). - * https://openapi-generator.tech - * Do not edit the class manually. - */ - - -package io.lakefs.clients.api.model; - -import com.google.gson.TypeAdapter; -import com.google.gson.annotations.JsonAdapter; -import com.google.gson.annotations.SerializedName; -import com.google.gson.stream.JsonReader; -import com.google.gson.stream.JsonWriter; -import io.swagger.annotations.ApiModel; -import io.swagger.annotations.ApiModelProperty; -import java.io.IOException; -import org.junit.Assert; -import org.junit.Ignore; -import org.junit.Test; - - -/** - * Model tests for AuthCapabilities - */ -public class AuthCapabilitiesTest { - private final AuthCapabilities model = new AuthCapabilities(); - - /** - * Model tests for AuthCapabilities - */ - @Test - public void testAuthCapabilities() { - // TODO: test AuthCapabilities - } - - /** - * Test the property 'inviteUser' - */ - @Test - public void inviteUserTest() { - // TODO: test inviteUser - } - - /** - * Test the property 'forgotPassword' - */ - @Test - public void forgotPasswordTest() { - // TODO: test forgotPassword - } - -} diff --git a/clients/java/src/test/java/io/lakefs/clients/api/model/UserCreationTest.java b/clients/java/src/test/java/io/lakefs/clients/api/model/UserCreationTest.java index b5e01e4b235..0a02112d852 100644 --- a/clients/java/src/test/java/io/lakefs/clients/api/model/UserCreationTest.java +++ b/clients/java/src/test/java/io/lakefs/clients/api/model/UserCreationTest.java @@ -48,12 +48,4 @@ public void idTest() { // TODO: test id } - /** - * Test the property 'inviteUser' - */ - @Test - public void inviteUserTest() { - // TODO: test inviteUser - } - } diff --git a/clients/python/.openapi-generator/FILES b/clients/python/.openapi-generator/FILES index 62467335172..ee312b51cfe 100644 --- a/clients/python/.openapi-generator/FILES +++ b/clients/python/.openapi-generator/FILES @@ -7,7 +7,6 @@ docs/ActionRun.md docs/ActionRunList.md docs/ActionsApi.md docs/AuthApi.md -docs/AuthCapabilities.md docs/AuthenticationToken.md docs/BranchCreation.md docs/BranchProtectionRule.md @@ -135,7 +134,6 @@ lakefs_client/model/access_key_credentials.py lakefs_client/model/acl.py lakefs_client/model/action_run.py lakefs_client/model/action_run_list.py -lakefs_client/model/auth_capabilities.py lakefs_client/model/authentication_token.py lakefs_client/model/branch_creation.py lakefs_client/model/branch_protection_rule.py @@ -235,7 +233,6 @@ test/test_action_run.py test/test_action_run_list.py test/test_actions_api.py test/test_auth_api.py -test/test_auth_capabilities.py test/test_authentication_token.py test/test_branch_creation.py test/test_branch_protection_rule.py diff --git a/clients/python/README.md b/clients/python/README.md index fb718049cc7..7cd40484621 100644 --- a/clients/python/README.md +++ b/clients/python/README.md @@ -173,7 +173,6 @@ Class | Method | HTTP request | Description *ImportApi* | [**import_status**](docs/ImportApi.md#import_status) | **GET** /repositories/{repository}/branches/{branch}/import | get import status *ImportApi* | [**ingest_range**](docs/ImportApi.md#ingest_range) | **POST** /repositories/{repository}/branches/ranges | create a lakeFS range file from the source uri *InternalApi* | [**create_branch_protection_rule_preflight**](docs/InternalApi.md#create_branch_protection_rule_preflight) | **GET** /repositories/{repository}/branch_protection/set_allowed | -*InternalApi* | [**get_auth_capabilities**](docs/InternalApi.md#get_auth_capabilities) | **GET** /auth/capabilities | list authentication capabilities supported *InternalApi* | [**get_setup_state**](docs/InternalApi.md#get_setup_state) | **GET** /setup_lakefs | check if the lakeFS installation is already set up *InternalApi* | [**post_stats_events**](docs/InternalApi.md#post_stats_events) | **POST** /statistics | post stats events, this endpoint is meant for internal use only *InternalApi* | [**set_garbage_collection_rules_preflight**](docs/InternalApi.md#set_garbage_collection_rules_preflight) | **GET** /repositories/{repository}/gc/rules/set_allowed | @@ -227,7 +226,6 @@ Class | Method | HTTP request | Description - [AccessKeyCredentials](docs/AccessKeyCredentials.md) - [ActionRun](docs/ActionRun.md) - [ActionRunList](docs/ActionRunList.md) - - [AuthCapabilities](docs/AuthCapabilities.md) - [AuthenticationToken](docs/AuthenticationToken.md) - [BranchCreation](docs/BranchCreation.md) - [BranchProtectionRule](docs/BranchProtectionRule.md) diff --git a/clients/python/docs/AuthApi.md b/clients/python/docs/AuthApi.md index 9502b89365e..3027f7fb243 100644 --- a/clients/python/docs/AuthApi.md +++ b/clients/python/docs/AuthApi.md @@ -763,7 +763,6 @@ with lakefs_client.ApiClient(configuration) as api_client: api_instance = auth_api.AuthApi(api_client) user_creation = UserCreation( id="id_example", - invite_user=True, ) # UserCreation | (optional) # example passing only required values which don't have defaults set diff --git a/clients/python/docs/AuthCapabilities.md b/clients/python/docs/AuthCapabilities.md deleted file mode 100644 index c01ce77ed33..00000000000 --- a/clients/python/docs/AuthCapabilities.md +++ /dev/null @@ -1,13 +0,0 @@ -# AuthCapabilities - - -## Properties -Name | Type | Description | Notes ------------- | ------------- | ------------- | ------------- -**invite_user** | **bool** | | [optional] -**forgot_password** | **bool** | | [optional] -**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] - -[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) - - diff --git a/clients/python/docs/InternalApi.md b/clients/python/docs/InternalApi.md index 42fe236887a..40579805683 100644 --- a/clients/python/docs/InternalApi.md +++ b/clients/python/docs/InternalApi.md @@ -5,7 +5,6 @@ All URIs are relative to *http://localhost/api/v1* Method | HTTP request | Description ------------- | ------------- | ------------- [**create_branch_protection_rule_preflight**](InternalApi.md#create_branch_protection_rule_preflight) | **GET** /repositories/{repository}/branch_protection/set_allowed | -[**get_auth_capabilities**](InternalApi.md#get_auth_capabilities) | **GET** /auth/capabilities | list authentication capabilities supported [**get_setup_state**](InternalApi.md#get_setup_state) | **GET** /setup_lakefs | check if the lakeFS installation is already set up [**post_stats_events**](InternalApi.md#post_stats_events) | **POST** /statistics | post stats events, this endpoint is meant for internal use only [**set_garbage_collection_rules_preflight**](InternalApi.md#set_garbage_collection_rules_preflight) | **GET** /repositories/{repository}/gc/rules/set_allowed | @@ -120,69 +119,6 @@ void (empty response body) [[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_auth_capabilities** -> AuthCapabilities get_auth_capabilities() - -list authentication capabilities supported - -### Example - - -```python -import time -import lakefs_client -from lakefs_client.api import internal_api -from lakefs_client.model.error import Error -from lakefs_client.model.auth_capabilities import AuthCapabilities -from pprint import pprint -# Defining the host is optional and defaults to http://localhost/api/v1 -# See configuration.py for a list of all supported configuration parameters. -configuration = lakefs_client.Configuration( - host = "http://localhost/api/v1" -) - - -# Enter a context with an instance of the API client -with lakefs_client.ApiClient() as api_client: - # Create an instance of the API class - api_instance = internal_api.InternalApi(api_client) - - # example, this endpoint has no required or optional parameters - try: - # list authentication capabilities supported - api_response = api_instance.get_auth_capabilities() - pprint(api_response) - except lakefs_client.ApiException as e: - print("Exception when calling InternalApi->get_auth_capabilities: %s\n" % e) -``` - - -### Parameters -This endpoint does not need any parameter. - -### Return type - -[**AuthCapabilities**](AuthCapabilities.md) - -### Authorization - -No authorization required - -### HTTP request headers - - - **Content-Type**: Not defined - - **Accept**: application/json - - -### HTTP response details - -| Status code | Description | Response headers | -|-------------|-------------|------------------| -**200** | auth capabilities | - | -**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_setup_state** > SetupState get_setup_state() diff --git a/clients/python/docs/UserCreation.md b/clients/python/docs/UserCreation.md index c3a70a16228..670f9734cdb 100644 --- a/clients/python/docs/UserCreation.md +++ b/clients/python/docs/UserCreation.md @@ -5,7 +5,6 @@ Name | Type | Description | Notes ------------ | ------------- | ------------- | ------------- **id** | **str** | a unique identifier for the user. | -**invite_user** | **bool** | | [optional] **any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional] [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/clients/python/lakefs_client/api/internal_api.py b/clients/python/lakefs_client/api/internal_api.py index 68b1538ae9b..230dfe79f71 100644 --- a/clients/python/lakefs_client/api/internal_api.py +++ b/clients/python/lakefs_client/api/internal_api.py @@ -22,7 +22,6 @@ none_type, validate_and_convert_types ) -from lakefs_client.model.auth_capabilities import AuthCapabilities from lakefs_client.model.comm_prefs_input import CommPrefsInput from lakefs_client.model.credentials_with_secret import CredentialsWithSecret from lakefs_client.model.error import Error @@ -98,48 +97,6 @@ def __init__(self, api_client=None): }, api_client=api_client ) - self.get_auth_capabilities_endpoint = _Endpoint( - settings={ - 'response_type': (AuthCapabilities,), - 'auth': [], - 'endpoint_path': '/auth/capabilities', - 'operation_id': 'get_auth_capabilities', - 'http_method': 'GET', - 'servers': None, - }, - params_map={ - 'all': [ - ], - 'required': [], - 'nullable': [ - ], - 'enum': [ - ], - 'validation': [ - ] - }, - root_map={ - 'validations': { - }, - 'allowed_values': { - }, - 'openapi_types': { - }, - 'attribute_map': { - }, - 'location_map': { - }, - 'collection_format_map': { - } - }, - headers_map={ - 'accept': [ - 'application/json' - ], - 'content_type': [], - }, - api_client=api_client - ) self.get_setup_state_endpoint = _Endpoint( settings={ 'response_type': (SetupState,), @@ -594,66 +551,6 @@ def create_branch_protection_rule_preflight( repository return self.create_branch_protection_rule_preflight_endpoint.call_with_http_info(**kwargs) - def get_auth_capabilities( - self, - **kwargs - ): - """list authentication capabilities supported # 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_auth_capabilities(async_req=True) - >>> result = thread.get() - - - Keyword Args: - _return_http_data_only (bool): response data without head status - code and headers. Default is True. - _preload_content (bool): if False, the urllib3.HTTPResponse object - will be returned without reading/decoding response data. - Default is True. - _request_timeout (int/float/tuple): 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. - Default is None. - _check_input_type (bool): specifies if type checking - should be done one the data sent to the server. - Default is True. - _check_return_type (bool): specifies if type checking - should be done one the data received from the server. - Default is True. - _host_index (int/None): specifies the index of the server - that we want to use. - Default is read from the configuration. - async_req (bool): execute request asynchronously - - Returns: - AuthCapabilities - If the method is called asynchronously, returns the request - thread. - """ - kwargs['async_req'] = kwargs.get( - 'async_req', False - ) - kwargs['_return_http_data_only'] = kwargs.get( - '_return_http_data_only', True - ) - kwargs['_preload_content'] = kwargs.get( - '_preload_content', True - ) - kwargs['_request_timeout'] = kwargs.get( - '_request_timeout', None - ) - kwargs['_check_input_type'] = kwargs.get( - '_check_input_type', True - ) - kwargs['_check_return_type'] = kwargs.get( - '_check_return_type', True - ) - kwargs['_host_index'] = kwargs.get('_host_index') - return self.get_auth_capabilities_endpoint.call_with_http_info(**kwargs) - def get_setup_state( self, **kwargs diff --git a/clients/python/lakefs_client/model/auth_capabilities.py b/clients/python/lakefs_client/model/auth_capabilities.py deleted file mode 100644 index aed57522ca0..00000000000 --- a/clients/python/lakefs_client/model/auth_capabilities.py +++ /dev/null @@ -1,260 +0,0 @@ -""" - lakeFS API - - lakeFS HTTP API # noqa: E501 - - The version of the OpenAPI document: 0.1.0 - Contact: services@treeverse.io - Generated by: https://openapi-generator.tech -""" - - -import re # noqa: F401 -import sys # noqa: F401 - -from lakefs_client.model_utils import ( # noqa: F401 - ApiTypeError, - ModelComposed, - ModelNormal, - ModelSimple, - cached_property, - change_keys_js_to_python, - convert_js_args_to_python_args, - date, - datetime, - file_type, - none_type, - validate_get_composed_info, -) -from ..model_utils import OpenApiModel -from lakefs_client.exceptions import ApiAttributeError - - - -class AuthCapabilities(ModelNormal): - """NOTE: This class is auto generated by OpenAPI Generator. - Ref: https://openapi-generator.tech - - Do not edit the class manually. - - Attributes: - allowed_values (dict): The key is the tuple path to the attribute - and the for var_name this is (var_name,). The value is a dict - with a capitalized key describing the allowed value and an allowed - value. These dicts store the allowed enum values. - attribute_map (dict): The key is attribute name - and the value is json key in definition. - discriminator_value_class_map (dict): A dict to go from the discriminator - variable value to the discriminator class name. - validations (dict): The key is the tuple path to the attribute - and the for var_name this is (var_name,). The value is a dict - that stores validations for max_length, min_length, max_items, - min_items, exclusive_maximum, inclusive_maximum, exclusive_minimum, - inclusive_minimum, and regex. - additional_properties_type (tuple): A tuple of classes accepted - as additional properties values. - """ - - allowed_values = { - } - - validations = { - } - - @cached_property - def additional_properties_type(): - """ - This must be a method because a model may have properties that are - of type self, this must run after the class is loaded - """ - return (bool, date, datetime, dict, float, int, list, str, none_type,) # noqa: E501 - - _nullable = False - - @cached_property - def openapi_types(): - """ - This must be a method because a model may have properties that are - of type self, this must run after the class is loaded - - Returns - openapi_types (dict): The key is attribute name - and the value is attribute type. - """ - return { - 'invite_user': (bool,), # noqa: E501 - 'forgot_password': (bool,), # noqa: E501 - } - - @cached_property - def discriminator(): - return None - - - attribute_map = { - 'invite_user': 'invite_user', # noqa: E501 - 'forgot_password': 'forgot_password', # noqa: E501 - } - - read_only_vars = { - } - - _composed_schemas = {} - - @classmethod - @convert_js_args_to_python_args - def _from_openapi_data(cls, *args, **kwargs): # noqa: E501 - """AuthCapabilities - a model defined in OpenAPI - - Keyword Args: - _check_type (bool): if True, values for parameters in openapi_types - will be type checked and a TypeError will be - raised if the wrong type is input. - Defaults to True - _path_to_item (tuple/list): This is a list of keys or values to - drill down to the model in received_data - when deserializing a response - _spec_property_naming (bool): True if the variable names in the input data - are serialized names, as specified in the OpenAPI document. - False if the variable names in the input data - are pythonic names, e.g. snake case (default) - _configuration (Configuration): the instance to use when - deserializing a file_type parameter. - If passed, type conversion is attempted - If omitted no type conversion is done. - _visited_composed_classes (tuple): This stores a tuple of - classes that we have traveled through so that - if we see that class again we will not use its - discriminator again. - When traveling through a discriminator, the - composed schema that is - is traveled through is added to this set. - For example if Animal has a discriminator - petType and we pass in "Dog", and the class Dog - allOf includes Animal, we move through Animal - once using the discriminator, and pick Dog. - Then in Dog, we will make an instance of the - Animal class but this time we won't travel - through its discriminator because we passed in - _visited_composed_classes = (Animal,) - invite_user (bool): [optional] # noqa: E501 - forgot_password (bool): [optional] # noqa: E501 - """ - - _check_type = kwargs.pop('_check_type', True) - _spec_property_naming = kwargs.pop('_spec_property_naming', False) - _path_to_item = kwargs.pop('_path_to_item', ()) - _configuration = kwargs.pop('_configuration', None) - _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) - - self = super(OpenApiModel, cls).__new__(cls) - - if args: - raise ApiTypeError( - "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( - args, - self.__class__.__name__, - ), - path_to_item=_path_to_item, - valid_classes=(self.__class__,), - ) - - self._data_store = {} - self._check_type = _check_type - self._spec_property_naming = _spec_property_naming - self._path_to_item = _path_to_item - self._configuration = _configuration - self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - - for var_name, var_value in kwargs.items(): - if var_name not in self.attribute_map and \ - self._configuration is not None and \ - self._configuration.discard_unknown_keys and \ - self.additional_properties_type is None: - # discard variable. - continue - setattr(self, var_name, var_value) - return self - - required_properties = set([ - '_data_store', - '_check_type', - '_spec_property_naming', - '_path_to_item', - '_configuration', - '_visited_composed_classes', - ]) - - @convert_js_args_to_python_args - def __init__(self, *args, **kwargs): # noqa: E501 - """AuthCapabilities - a model defined in OpenAPI - - Keyword Args: - _check_type (bool): if True, values for parameters in openapi_types - will be type checked and a TypeError will be - raised if the wrong type is input. - Defaults to True - _path_to_item (tuple/list): This is a list of keys or values to - drill down to the model in received_data - when deserializing a response - _spec_property_naming (bool): True if the variable names in the input data - are serialized names, as specified in the OpenAPI document. - False if the variable names in the input data - are pythonic names, e.g. snake case (default) - _configuration (Configuration): the instance to use when - deserializing a file_type parameter. - If passed, type conversion is attempted - If omitted no type conversion is done. - _visited_composed_classes (tuple): This stores a tuple of - classes that we have traveled through so that - if we see that class again we will not use its - discriminator again. - When traveling through a discriminator, the - composed schema that is - is traveled through is added to this set. - For example if Animal has a discriminator - petType and we pass in "Dog", and the class Dog - allOf includes Animal, we move through Animal - once using the discriminator, and pick Dog. - Then in Dog, we will make an instance of the - Animal class but this time we won't travel - through its discriminator because we passed in - _visited_composed_classes = (Animal,) - invite_user (bool): [optional] # noqa: E501 - forgot_password (bool): [optional] # noqa: E501 - """ - - _check_type = kwargs.pop('_check_type', True) - _spec_property_naming = kwargs.pop('_spec_property_naming', False) - _path_to_item = kwargs.pop('_path_to_item', ()) - _configuration = kwargs.pop('_configuration', None) - _visited_composed_classes = kwargs.pop('_visited_composed_classes', ()) - - if args: - raise ApiTypeError( - "Invalid positional arguments=%s passed to %s. Remove those invalid positional arguments." % ( - args, - self.__class__.__name__, - ), - path_to_item=_path_to_item, - valid_classes=(self.__class__,), - ) - - self._data_store = {} - self._check_type = _check_type - self._spec_property_naming = _spec_property_naming - self._path_to_item = _path_to_item - self._configuration = _configuration - self._visited_composed_classes = _visited_composed_classes + (self.__class__,) - - for var_name, var_value in kwargs.items(): - if var_name not in self.attribute_map and \ - self._configuration is not None and \ - self._configuration.discard_unknown_keys and \ - self.additional_properties_type is None: - # discard variable. - continue - setattr(self, var_name, var_value) - if var_name in self.read_only_vars: - raise ApiAttributeError(f"`{var_name}` is a read-only attribute. Use `from_openapi_data` to instantiate " - f"class with read only attributes.") diff --git a/clients/python/lakefs_client/model/user_creation.py b/clients/python/lakefs_client/model/user_creation.py index db179bbfb68..ba80d46b3a9 100644 --- a/clients/python/lakefs_client/model/user_creation.py +++ b/clients/python/lakefs_client/model/user_creation.py @@ -83,7 +83,6 @@ def openapi_types(): """ return { 'id': (str,), # noqa: E501 - 'invite_user': (bool,), # noqa: E501 } @cached_property @@ -93,7 +92,6 @@ def discriminator(): attribute_map = { 'id': 'id', # noqa: E501 - 'invite_user': 'invite_user', # noqa: E501 } read_only_vars = { @@ -140,7 +138,6 @@ def _from_openapi_data(cls, id, *args, **kwargs): # noqa: E501 Animal class but this time we won't travel through its discriminator because we passed in _visited_composed_classes = (Animal,) - invite_user (bool): [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) @@ -226,7 +223,6 @@ def __init__(self, id, *args, **kwargs): # noqa: E501 Animal class but this time we won't travel through its discriminator because we passed in _visited_composed_classes = (Animal,) - invite_user (bool): [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) diff --git a/clients/python/lakefs_client/models/__init__.py b/clients/python/lakefs_client/models/__init__.py index cf2a403a395..4e9561b65ee 100644 --- a/clients/python/lakefs_client/models/__init__.py +++ b/clients/python/lakefs_client/models/__init__.py @@ -13,7 +13,6 @@ from lakefs_client.model.access_key_credentials import AccessKeyCredentials from lakefs_client.model.action_run import ActionRun from lakefs_client.model.action_run_list import ActionRunList -from lakefs_client.model.auth_capabilities import AuthCapabilities from lakefs_client.model.authentication_token import AuthenticationToken from lakefs_client.model.branch_creation import BranchCreation from lakefs_client.model.branch_protection_rule import BranchProtectionRule diff --git a/clients/python/test/test_auth_capabilities.py b/clients/python/test/test_auth_capabilities.py deleted file mode 100644 index 06c5de04c25..00000000000 --- a/clients/python/test/test_auth_capabilities.py +++ /dev/null @@ -1,36 +0,0 @@ -""" - lakeFS API - - lakeFS HTTP API # noqa: E501 - - The version of the OpenAPI document: 0.1.0 - Contact: services@treeverse.io - Generated by: https://openapi-generator.tech -""" - - -import sys -import unittest - -import lakefs_client -from lakefs_client.model.auth_capabilities import AuthCapabilities - - -class TestAuthCapabilities(unittest.TestCase): - """AuthCapabilities unit test stubs""" - - def setUp(self): - pass - - def tearDown(self): - pass - - def testAuthCapabilities(self): - """Test AuthCapabilities""" - # FIXME: construct object with mandatory attributes with example values - # model = AuthCapabilities() # noqa: E501 - pass - - -if __name__ == '__main__': - unittest.main() diff --git a/clients/python/test/test_internal_api.py b/clients/python/test/test_internal_api.py index 5ccb8f17450..0a5bb8de34c 100644 --- a/clients/python/test/test_internal_api.py +++ b/clients/python/test/test_internal_api.py @@ -30,13 +30,6 @@ def test_create_branch_protection_rule_preflight(self): """ pass - def test_get_auth_capabilities(self): - """Test case for get_auth_capabilities - - list authentication capabilities supported # noqa: E501 - """ - pass - def test_get_setup_state(self): """Test case for get_setup_state diff --git a/cmd/lakefs/cmd/run.go b/cmd/lakefs/cmd/run.go index 966079d80c5..800ccd264e3 100644 --- a/cmd/lakefs/cmd/run.go +++ b/cmd/lakefs/cmd/run.go @@ -22,7 +22,6 @@ import ( "github.com/treeverse/lakefs/pkg/api" "github.com/treeverse/lakefs/pkg/auth" "github.com/treeverse/lakefs/pkg/auth/crypt" - "github.com/treeverse/lakefs/pkg/auth/email" authparams "github.com/treeverse/lakefs/pkg/auth/params" authremote "github.com/treeverse/lakefs/pkg/auth/remoteauthenticator" "github.com/treeverse/lakefs/pkg/block" @@ -106,11 +105,6 @@ var runCmd = &cobra.Command{ logger.WithError(err).Fatal("Failure on schema validation") } - emailer, err := email.NewEmailer(email.Params(cfg.Email)) - if err != nil { - logger.WithError(err).Fatal("Emailer has not been properly configured, check the values in sender field") - } - migrator := kv.NewDatabaseMigrator(kvParams) multipartTracker := multipart.NewTracker(kvStore) actionsStore := actions.NewActionsKVStore(kvStore) @@ -124,17 +118,11 @@ var runCmd = &cobra.Command{ logger.WithError(err).Fatal("Unsupported auth mode") } if cfg.IsAuthTypeAPI() { - var apiEmailer *email.Emailer - if !cfg.Auth.API.SupportsInvites { - // invites not supported by API - delegate it to emailer - apiEmailer = emailer - } authService, err = auth.NewAPIAuthService( cfg.Auth.API.Endpoint, cfg.Auth.API.Token.SecureValue(), crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), authparams.ServiceCache(cfg.Auth.Cache), - apiEmailer, logger.WithField("service", "auth_api"), ) if err != nil { @@ -144,7 +132,6 @@ var runCmd = &cobra.Command{ authService = auth.NewAuthService( kvStore, crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), - emailer, authparams.ServiceCache(cfg.Auth.Cache), logger.WithField("service", "auth_service"), ) @@ -263,7 +250,6 @@ var runCmd = &cobra.Command{ actionsService, auditChecker, logger.WithField("service", "api_gateway"), - emailer, cfg.Gateways.S3.DomainNames, cfg.UISnippets(), upload.DefaultPathProvider, diff --git a/cmd/lakefs/cmd/setup.go b/cmd/lakefs/cmd/setup.go index 7c044aa57be..b15c61a6c6e 100644 --- a/cmd/lakefs/cmd/setup.go +++ b/cmd/lakefs/cmd/setup.go @@ -74,7 +74,7 @@ var setupCmd = &cobra.Command{ defer kvStore.Close() logger := logging.ContextUnavailable() authLogger := logger.WithField("service", "auth_service") - authService = auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), nil, authparams.ServiceCache(cfg.Auth.Cache), authLogger) + authService = auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), authparams.ServiceCache(cfg.Auth.Cache), authLogger) metadataManager = auth.NewKVMetadataManager(version.Version, cfg.Installation.FixedID, cfg.Database.Type, kvStore) cloudMetadataProvider := stats.BuildMetadataProvider(logger, cfg) diff --git a/cmd/lakefs/cmd/superuser.go b/cmd/lakefs/cmd/superuser.go index a0a5030fff9..5e35c991003 100644 --- a/cmd/lakefs/cmd/superuser.go +++ b/cmd/lakefs/cmd/superuser.go @@ -59,7 +59,7 @@ var superuserCmd = &cobra.Command{ fmt.Printf("Failed to open KV store: %s\n", err) os.Exit(1) } - authService := auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), nil, authparams.ServiceCache(cfg.Auth.Cache), logger.WithField("service", "auth_service")) + authService := auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), authparams.ServiceCache(cfg.Auth.Cache), logger.WithField("service", "auth_service")) authMetadataManager := auth.NewKVMetadataManager(version.Version, cfg.Installation.FixedID, cfg.Database.Type, kvStore) metadataProvider := stats.BuildMetadataProvider(logger, cfg) diff --git a/docs/assets/js/swagger.yml b/docs/assets/js/swagger.yml index 2138338a30b..de7e3cc26a4 100644 --- a/docs/assets/js/swagger.yml +++ b/docs/assets/js/swagger.yml @@ -698,8 +698,6 @@ components: description: Unix Epoch in seconds friendly_name: type: string - email: - type: string CurrentUser: type: object @@ -709,15 +707,12 @@ components: user: $ref: "#/components/schemas/User" - UserCreation: type: object properties: id: type: string description: a unique identifier for the user. - invite_user: - type: boolean required: - id @@ -814,6 +809,7 @@ components: - featureUpdates - securityUpdates + Credentials: type: object required: @@ -882,14 +878,6 @@ components: items: $ref: "#/components/schemas/Group" - AuthCapabilities: - type: object - properties: - invite_user: - type: boolean - forgot_password: - type: boolean - UserList: type: object required: @@ -1564,24 +1552,6 @@ paths: default: $ref: "#/components/responses/ServerError" - - /auth/capabilities: - get: - tags: - - internal - operationId: getAuthCapabilities - summary: list authentication capabilities supported - security: [] - responses: - 200: - description: auth capabilities - content: - application/json: - schema: - $ref: "#/components/schemas/AuthCapabilities" - default: - $ref: "#/components/responses/ServerError" - /auth/users: get: tags: diff --git a/pkg/api/controller.go b/pkg/api/controller.go index 35b4df62d8d..0e7ad03de58 100644 --- a/pkg/api/controller.go +++ b/pkg/api/controller.go @@ -27,7 +27,6 @@ import ( "github.com/treeverse/lakefs/pkg/api/apiutil" "github.com/treeverse/lakefs/pkg/auth" "github.com/treeverse/lakefs/pkg/auth/acl" - "github.com/treeverse/lakefs/pkg/auth/email" "github.com/treeverse/lakefs/pkg/auth/model" "github.com/treeverse/lakefs/pkg/auth/setup" "github.com/treeverse/lakefs/pkg/block" @@ -92,7 +91,6 @@ type Controller struct { Actions actionsHandler AuditChecker AuditChecker Logger logging.Logger - Emailer *email.Emailer sessionStore sessions.Store PathProvider upload.PathProvider otfDiffService *tablediff.Service @@ -148,15 +146,6 @@ func (c *Controller) PrepareGarbageCollectionUncommitted(w http.ResponseWriter, }) } -func (c *Controller) GetAuthCapabilities(w http.ResponseWriter, r *http.Request) { - inviteSupported := c.Auth.IsInviteSupported() - emailSupported := c.Emailer.Params.SMTPHost != "" - writeResponse(w, r, http.StatusOK, apigen.AuthCapabilities{ - InviteUser: &inviteSupported, - ForgotPassword: &emailSupported, - }) -} - func (c *Controller) DeleteObjects(w http.ResponseWriter, r *http.Request, body apigen.DeleteObjectsJSONRequestBody, repository, branch string) { ctx := r.Context() c.LogAction(ctx, "delete_objects", r, repository, branch, "") @@ -1068,7 +1057,6 @@ func (c *Controller) ListUsers(w http.ResponseWriter, r *http.Request, params ap } func (c *Controller) CreateUser(w http.ResponseWriter, r *http.Request, body apigen.CreateUserJSONRequestBody) { - invite := swag.BoolValue(body.InviteUser) username := body.Id // Check that username is valid @@ -1079,16 +1067,6 @@ func (c *Controller) CreateUser(w http.ResponseWriter, r *http.Request, body api } var parsedEmail *string - if invite { - addr, err := mail.ParseAddress(username) - if err != nil { - c.Logger.WithError(err).WithField("user_id", username).Warn("failed parsing email") - writeError(w, r, http.StatusBadRequest, "Invalid email format") - return - } - username = strings.ToLower(addr.Address) - parsedEmail = &addr.Address - } if !c.authorize(w, r, permissions.Node{ Permission: permissions.Permission{ Action: permissions.CreateUserAction, @@ -1099,15 +1077,6 @@ func (c *Controller) CreateUser(w http.ResponseWriter, r *http.Request, body api } ctx := r.Context() c.LogAction(ctx, "create_user", r, "", "", "") - if invite { - err := c.Auth.InviteUser(ctx, *parsedEmail) - if c.handleAPIError(ctx, w, r, err) { - c.Logger.WithError(err).WithField("email", *parsedEmail).Warn("failed creating user") - return - } - writeResponse(w, r, http.StatusCreated, apigen.User{Id: *parsedEmail}) - return - } u := &model.User{ CreatedAt: time.Now().UTC(), Username: username, @@ -4529,7 +4498,7 @@ func resolvePathList(objects, prefixes *[]string) []catalog.PathRecord { return pathRecords } -func NewController(cfg *config.Config, catalog catalog.Interface, authenticator auth.Authenticator, authService auth.Service, blockAdapter block.Adapter, metadataManager auth.MetadataManager, migrator Migrator, collector stats.Collector, cloudMetadataProvider cloud.MetadataProvider, actions actionsHandler, auditChecker AuditChecker, logger logging.Logger, emailer *email.Emailer, sessionStore sessions.Store, pathProvider upload.PathProvider, otfDiffService *tablediff.Service) *Controller { +func NewController(cfg *config.Config, catalog catalog.Interface, authenticator auth.Authenticator, authService auth.Service, blockAdapter block.Adapter, metadataManager auth.MetadataManager, migrator Migrator, collector stats.Collector, cloudMetadataProvider cloud.MetadataProvider, actions actionsHandler, auditChecker AuditChecker, logger logging.Logger, sessionStore sessions.Store, pathProvider upload.PathProvider, otfDiffService *tablediff.Service) *Controller { return &Controller{ Config: cfg, Catalog: catalog, @@ -4543,7 +4512,6 @@ func NewController(cfg *config.Config, catalog catalog.Interface, authenticator Actions: actions, AuditChecker: auditChecker, Logger: logger, - Emailer: emailer, sessionStore: sessionStore, PathProvider: pathProvider, otfDiffService: otfDiffService, diff --git a/pkg/api/serve.go b/pkg/api/serve.go index cfc8b4dcf73..c8873039b18 100644 --- a/pkg/api/serve.go +++ b/pkg/api/serve.go @@ -16,7 +16,6 @@ import ( "github.com/treeverse/lakefs/pkg/api/apiutil" "github.com/treeverse/lakefs/pkg/api/params" "github.com/treeverse/lakefs/pkg/auth" - "github.com/treeverse/lakefs/pkg/auth/email" "github.com/treeverse/lakefs/pkg/block" "github.com/treeverse/lakefs/pkg/catalog" "github.com/treeverse/lakefs/pkg/cloud" @@ -35,7 +34,7 @@ const ( extensionValidationExcludeBody = "x-validation-exclude-body" ) -func Serve(cfg *config.Config, catalog catalog.Interface, middlewareAuthenticator auth.Authenticator, authService auth.Service, blockAdapter block.Adapter, metadataManager auth.MetadataManager, migrator Migrator, collector stats.Collector, cloudMetadataProvider cloud.MetadataProvider, actions actionsHandler, auditChecker AuditChecker, logger logging.Logger, emailer *email.Emailer, gatewayDomains []string, snippets []params.CodeSnippet, pathProvider upload.PathProvider, otfService *tablediff.Service) http.Handler { +func Serve(cfg *config.Config, catalog catalog.Interface, middlewareAuthenticator auth.Authenticator, authService auth.Service, blockAdapter block.Adapter, metadataManager auth.MetadataManager, migrator Migrator, collector stats.Collector, cloudMetadataProvider cloud.MetadataProvider, actions actionsHandler, auditChecker AuditChecker, logger logging.Logger, gatewayDomains []string, snippets []params.CodeSnippet, pathProvider upload.PathProvider, otfService *tablediff.Service) http.Handler { logger.Info("initialize OpenAPI server") swagger, err := apigen.GetSwagger() if err != nil { @@ -57,7 +56,7 @@ func Serve(cfg *config.Config, catalog catalog.Interface, middlewareAuthenticato AuthMiddleware(logger, swagger, middlewareAuthenticator, authService, sessionStore, &oidcConfig, &cookieAuthConfig), MetricsMiddleware(swagger), ) - controller := NewController(cfg, catalog, middlewareAuthenticator, authService, blockAdapter, metadataManager, migrator, collector, cloudMetadataProvider, actions, auditChecker, logger, emailer, sessionStore, pathProvider, otfService) + controller := NewController(cfg, catalog, middlewareAuthenticator, authService, blockAdapter, metadataManager, migrator, collector, cloudMetadataProvider, actions, auditChecker, logger, sessionStore, pathProvider, otfService) apigen.HandlerFromMuxWithBaseURL(controller, apiRouter, apiutil.BaseURL) r.Mount("/_health", httputil.ServeHealth()) diff --git a/pkg/api/serve_test.go b/pkg/api/serve_test.go index b4d8da130ec..6d940c54792 100644 --- a/pkg/api/serve_test.go +++ b/pkg/api/serve_test.go @@ -12,7 +12,6 @@ import ( "time" "github.com/deepmap/oapi-codegen/pkg/securityprovider" - "github.com/go-openapi/swag" "github.com/spf13/viper" "github.com/treeverse/lakefs/pkg/actions" "github.com/treeverse/lakefs/pkg/api" @@ -20,7 +19,6 @@ import ( "github.com/treeverse/lakefs/pkg/api/apiutil" "github.com/treeverse/lakefs/pkg/auth" "github.com/treeverse/lakefs/pkg/auth/crypt" - "github.com/treeverse/lakefs/pkg/auth/email" authmodel "github.com/treeverse/lakefs/pkg/auth/model" authparams "github.com/treeverse/lakefs/pkg/auth/params" "github.com/treeverse/lakefs/pkg/block" @@ -106,8 +104,7 @@ func createUserWithDefaultGroup(t testing.TB, clt apigen.ClientWithResponsesInte t.Helper() // create the user createUsrRes, err := clt.CreateUserWithResponse(context.Background(), apigen.CreateUserJSONRequestBody{ - Id: "test@example.com", - InviteUser: swag.Bool(false), + Id: "test@example.com", }) testutil.Must(t, err) if createUsrRes.JSON201 == nil { @@ -146,7 +143,7 @@ func setupHandlerWithWalkerFactory(t testing.TB, factory catalog.WalkerFactory) kvStore := kvtest.GetStore(ctx, t) actionsStore := actions.NewActionsKVStore(kvStore) idGen := &actions.DecreasingIDGenerator{} - authService := auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), nil, authparams.ServiceCache{ + authService := auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), authparams.ServiceCache{ Enabled: false, }, logging.ContextUnavailable()) meta := auth.NewKVMetadataManager("serve_test", cfg.Installation.FixedID, cfg.Database.Type, kvStore) @@ -187,12 +184,11 @@ func setupHandlerWithWalkerFactory(t testing.TB, factory catalog.WalkerFactory) }) auditChecker := version.NewDefaultAuditChecker(cfg.Security.AuditCheckURL, "", nil) - emailer, err := email.NewEmailer(email.Params(cfg.Email)) otfDiffService := tablediff.NewMockService() testutil.Must(t, err) - handler := api.Serve(cfg, c, authenticator, authService, c.BlockAdapter, meta, migrator, collector, nil, actionsService, auditChecker, logging.ContextUnavailable(), emailer, nil, nil, upload.DefaultPathProvider, otfDiffService) + handler := api.Serve(cfg, c, authenticator, authService, c.BlockAdapter, meta, migrator, collector, nil, actionsService, auditChecker, logging.ContextUnavailable(), nil, nil, upload.DefaultPathProvider, otfDiffService) return handler, &dependencies{ blocks: c.BlockAdapter, diff --git a/pkg/auth/email/emailer.go b/pkg/auth/email/emailer.go deleted file mode 100644 index d0fb05dad7f..00000000000 --- a/pkg/auth/email/emailer.go +++ /dev/null @@ -1,104 +0,0 @@ -package email - -import ( - "errors" - "fmt" - "net/mail" - "time" - - "golang.org/x/time/rate" - "gopkg.in/gomail.v2" -) - -var ( - ErrRateLimitExceeded = errors.New("rate limit exceeded") - ErrNoSMTPHostConfigured = errors.New("no smtp host configured") - ErrNoSenderConfigured = errors.New("no sender configured") - ErrNoRecipientConfigured = errors.New("no recipient configured") - ErrSenderMisconfigured = errors.New("sender misconfigured") -) - -type DialAndSender interface { - DialAndSend(m ...*gomail.Message) error -} - -type Emailer struct { - Params Params - Dialer DialAndSender - Limiter *rate.Limiter -} - -type Params struct { - SMTPHost string - SMTPPort int - UseSSL bool - Username string - Password string - LocalName string - Sender string - LimitEveryDuration time.Duration - Burst int - LakefsBaseURL string -} - -func NewEmailer(p Params) (*Emailer, error) { - if p.SMTPHost != "" { - _, err := mail.ParseAddress(p.Sender) - if err != nil { - return nil, fmt.Errorf("%w: %s", ErrSenderMisconfigured, err) - } - } - dialer := gomail.NewDialer(p.SMTPHost, p.SMTPPort, p.Username, p.Password) - dialer.SSL = p.UseSSL - dialer.LocalName = p.LocalName - limiter := rate.NewLimiter(rate.Every(p.LimitEveryDuration), p.Burst) - return &Emailer{ - Params: p, - Dialer: dialer, - Limiter: limiter, - }, nil -} - -func (e *Emailer) SendEmail(receivers []string, subject string, body string, attachmentFilePath []string) error { - if e.Params.SMTPHost == "" { - return ErrNoSMTPHostConfigured - } - if e.Params.Sender == "" { - return ErrNoSenderConfigured - } - if len(receivers) == 0 { - return ErrNoRecipientConfigured - } - msg := gomail.NewMessage() - msg.SetHeader("From", e.Params.Sender) - msg.SetHeader("To", receivers...) - msg.SetHeader("Subject", subject) - msg.SetBody("text/html", body) - for _, f := range attachmentFilePath { - msg.Attach(f) - } - return e.Dialer.DialAndSend(msg) -} - -func (e *Emailer) SendEmailWithLimit(receivers []string, subject string, body string, attachmentFilePath []string) error { - if !e.Limiter.Allow() { - return ErrRateLimitExceeded - } - return e.SendEmail(receivers, subject, body, attachmentFilePath) -} - -func (e *Emailer) SendResetPasswordEmail(receivers []string, params map[string]string) error { - body, err := buildEmailByTemplate(resetEmailTemplate, e.Params.LakefsBaseURL, resetPasswordURLPath, params) - if err != nil { - return err - } - return e.SendEmailWithLimit(receivers, resetPasswordEmailSubject, body, nil) -} - -func (e *Emailer) SendInviteUserEmail(receivers []string, params map[string]string) error { - body, err := buildEmailByTemplate(inviteUserTemplate, e.Params.LakefsBaseURL, inviteUserURLPath, params) - if err != nil { - return err - } - return e.SendEmailWithLimit(receivers, inviteUserWEmailSubject, body, nil) -} diff --git a/pkg/auth/email/emailer_test.go b/pkg/auth/email/emailer_test.go deleted file mode 100644 index 44d5fbbcf93..00000000000 --- a/pkg/auth/email/emailer_test.go +++ /dev/null @@ -1,223 +0,0 @@ -package email_test - -import ( - _ "embed" - "errors" - "math" - "strings" - "testing" - "time" - - "github.com/treeverse/lakefs/pkg/auth/email" - "github.com/treeverse/lakefs/pkg/testutil" - "golang.org/x/time/rate" - "gopkg.in/gomail.v2" -) - -var ( - //go:embed testdata/invite_user.golden - inviteUserGolden string - - //go:embed testdata/reset_password.golden - resetPasswordGolden string -) - -type MockDialer struct { - Message []*gomail.Message -} - -func (d *MockDialer) DialAndSend(m ...*gomail.Message) error { - d.Message = m - return nil -} - -func TestNewEmailer(t *testing.T) { - tests := []struct { - name string - smtpHost string - sender string - expected error - }{ - {name: "missing_smtp_host", smtpHost: "", sender: "bar", expected: nil}, - {name: "missing_sender", smtpHost: "foo", sender: "", expected: email.ErrSenderMisconfigured}, - {name: "missing_smtp_host_and_sender", smtpHost: "", sender: "", expected: nil}, - {name: "misconfigured_sender", smtpHost: "test.com", sender: "bar", expected: email.ErrSenderMisconfigured}, - {name: "noraml", smtpHost: "test.com", sender: "alice@testing.com", expected: nil}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - p := email.Params{ - SMTPHost: tt.smtpHost, - Sender: tt.sender, - } - emailer, err := email.NewEmailer(p) - if err == nil && emailer == nil { - t.Errorf("expected emailer, got nil pointer") - } - if !errors.Is(err, tt.expected) { - t.Errorf("expected err: %s got err: %s", tt.expected, err) - } - }) - } -} - -func TestSendEmail_Params(t *testing.T) { - p := email.Params{} - emailer, err := email.NewEmailer(p) - emailer.Dialer = &MockDialer{} - testutil.Must(t, err) - tests := []struct { - name string - smtpHost string - sender string - receiver []string - expected error - }{ - {name: "normal", smtpHost: "test@test.com", sender: "alice@test.com", receiver: []string{"bob@test.com"}, expected: nil}, - {name: "missing_smtp_host", smtpHost: "", sender: "alice@test.com", receiver: []string{"bob@test.com"}, expected: email.ErrNoSMTPHostConfigured}, - {name: "missing_sender", smtpHost: "test@test.com", sender: "", receiver: []string{"bob@test.com"}, expected: email.ErrNoSenderConfigured}, - {name: "missing_recipient", smtpHost: "test@test.com", sender: "alice@test.com", receiver: []string{}, expected: email.ErrNoRecipientConfigured}, - {name: "missing_smtp_host_and_sender", smtpHost: "", sender: "", receiver: []string{"bob@test.com"}, expected: email.ErrNoSMTPHostConfigured}, - {name: "missing_smtp_host_and_recipient", smtpHost: "", sender: "alice@test.com", receiver: []string{}, expected: email.ErrNoSMTPHostConfigured}, - {name: "missing_all", smtpHost: "", sender: "", receiver: []string{}, expected: email.ErrNoSMTPHostConfigured}, - {name: "missing_sender_and_recipient", smtpHost: "test@test.com", sender: "", receiver: []string{}, expected: email.ErrNoSenderConfigured}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - emailer.Params.SMTPHost, emailer.Params.Sender = tt.smtpHost, tt.sender - err = emailer.SendEmail(tt.receiver, "bar", "baz", nil) - if !errors.Is(err, tt.expected) { - t.Errorf("expected err: %s got err: %s", tt.expected, err) - } - }) - } -} - -func TestSendEmail_Headers(t *testing.T) { - p := email.Params{ - SMTPHost: "abc@test.com", - Sender: "test@test.com", - } - d := MockDialer{} - emailer := email.Emailer{ - Params: p, - Dialer: &d, - } - const subject = "testSubject" - const receiver = "receiver@test.com" - err := emailer.SendEmail([]string{receiver}, subject, "", nil) - testutil.Must(t, err) - if len(d.Message) != 1 { - t.Fatalf("message length %d, expected 1", len(d.Message)) - } - headers := map[string]string{ - "From": p.Sender, - "To": receiver, - "Subject": subject, - } - for k, v := range headers { - header := d.Message[0].GetHeader(k)[0] - if header != v { - t.Errorf("got header: %s, expected header: %s", header, v) - } - } -} - -func TestSendEmailWithLimit(t *testing.T) { - p := email.Params{SMTPHost: "test.com", Sender: "alice@testing.com"} - emailer, err := email.NewEmailer(p) - testutil.Must(t, err) - d := &MockDialer{} - emailer.Dialer = d - tests := []struct { - name string - limitEvery time.Duration - burst int - expect error - }{ - {name: "normal", limitEvery: rate.InfDuration, burst: math.MaxInt, expect: nil}, - {name: "zero_burst", limitEvery: rate.InfDuration, burst: 0, expect: email.ErrRateLimitExceeded}, - {name: "zero_time", limitEvery: 0, burst: math.MaxInt, expect: nil}, - {name: "zero_burst_and_time", limitEvery: 0, burst: 0, expect: email.ErrRateLimitExceeded}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - emailer.Limiter = rate.NewLimiter(rate.Limit(tt.limitEvery), tt.burst) - err := emailer.SendEmailWithLimit([]string{"receiver@test.com"}, "foo", "", nil) - if err == nil && len(d.Message) < 1 { - t.Errorf("expected message to be sent") - } - if !errors.Is(err, tt.expect) { - t.Errorf("got err: %s, expected err %s", err, tt.expect) - } - }) - } -} - -func TestSendResetPasswordAndInviteUserEmail(t *testing.T) { - // Burst value is set to 0, so any call to SendEmailWithLimit should result in ErrRateLimitExceeded - // thus verifying that SendEmailWithLimit was called - p := email.Params{Burst: 0, LimitEveryDuration: time.Minute} - emailer, err := email.NewEmailer(p) - testutil.Must(t, err) - receivers := []string{"foo"} - params := map[string]string{} - t.Run("invite_user", func(t *testing.T) { - err := emailer.SendInviteUserEmail(receivers, params) - if !errors.Is(err, email.ErrRateLimitExceeded) { - t.Errorf("expected error: %s got error: %s", email.ErrRateLimitExceeded, err) - } - }) - t.Run("reset_password", func(t *testing.T) { - err := emailer.SendResetPasswordEmail(receivers, params) - if !errors.Is(err, email.ErrRateLimitExceeded) { - t.Errorf("expected error: %s got error: %s", email.ErrRateLimitExceeded, err) - } - }) -} - -func TestEmailerSendEmailBody(t *testing.T) { - p := email.Params{ - SMTPHost: "abc@test.com", - Sender: "test@test.com", - LimitEveryDuration: time.Minute, - Burst: math.MaxInt, - } - d := MockDialer{} - lim := rate.NewLimiter(rate.Every(p.LimitEveryDuration), p.Burst) - emailer := email.Emailer{ - Params: p, - Dialer: &d, - Limiter: lim, - } - m := map[string]string{ - "paramx": "foo", - "paramy": "bar", - } - receivers := []string{"receiver@test.com"} - - tests := []struct { - name string - op func(receivers []string, params map[string]string) error - expectedBody string - }{ - {name: "reset_password", op: emailer.SendResetPasswordEmail, expectedBody: resetPasswordGolden}, - {name: "invite_user", op: emailer.SendInviteUserEmail, expectedBody: inviteUserGolden}, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - err := tt.op(receivers, m) - testutil.Must(t, err) - if len(d.Message) != 1 { - t.Fatalf("message length %d, expected 1", len(d.Message)) - } - var builder strings.Builder - _, err = d.Message[0].WriteTo(&builder) - testutil.Must(t, err) - msg := strings.ReplaceAll(builder.String(), "\r\n", "\n") - if !strings.Contains(msg, tt.expectedBody) { - t.Errorf("got email '%s', expected to match %s", msg, tt.expectedBody) - } - }) - } -} diff --git a/pkg/auth/email/invite_user_template.html b/pkg/auth/email/invite_user_template.html deleted file mode 100644 index 9b170b3b733..00000000000 --- a/pkg/auth/email/invite_user_template.html +++ /dev/null @@ -1,5 +0,0 @@ -Hello,
-You have been invited to join lakeFS
-Browse to lakeFS user activation page to set up your account
-Thanks
-The lakeFS team
diff --git a/pkg/auth/email/reset_email_template.html b/pkg/auth/email/reset_email_template.html deleted file mode 100644 index d5724dcdc7d..00000000000 --- a/pkg/auth/email/reset_email_template.html +++ /dev/null @@ -1,6 +0,0 @@ -Hello,
-A request has been received to change the password to your account,
-Browse to here to reset your password
-If you did not initiate this request you can please disregard this email.
-Thanks
-The lakeFS team
\ No newline at end of file diff --git a/pkg/auth/email/template.go b/pkg/auth/email/template.go deleted file mode 100644 index 73e22f7c490..00000000000 --- a/pkg/auth/email/template.go +++ /dev/null @@ -1,62 +0,0 @@ -package email - -import ( - _ "embed" - "html/template" - "net/url" - "path" - "strings" -) - -const ( - resetPasswordURLPath = "/auth/resetpassword" //#nosec - inviteUserURLPath = "/auth/users/create" //#nosec - - resetPasswordEmailSubject = "Reset Password Request for your lakeFS account" - inviteUserWEmailSubject = "You have been invited to lakeFS" -) - -var ( - //go:embed invite_user_template.html - inviteEmailContent string - inviteUserTemplate = template.Must(template.New("inviteUserTemplate").Parse(inviteEmailContent)) - - //go:embed reset_email_template.html - resetEmailContent string - resetEmailTemplate = template.Must(template.New("resetEmailTemplate").Parse(resetEmailContent)) -) - -type TemplateParams struct { - URL string -} - -// buildURL takes in the baseURL that was configured for email purposes and adds to it the relevant path and params to -// create a URL string that directs to the proper page, while passing the nessacery params -func buildURL(baseURL string, pth string, values map[string]string) (string, error) { - u, err := url.Parse(baseURL) - if err != nil { - return "", err - } - u.Path = path.Join(u.Path, pth) - params := u.Query() - for prm, value := range values { - params.Add(prm, value) - } - u.RawQuery = params.Encode() - return u.String(), nil -} - -func buildEmailByTemplate(tmpl *template.Template, host string, path string, params map[string]string) (string, error) { - u, err := buildURL(host, path, params) - if err != nil { - return "", err - } - var builder strings.Builder - l := TemplateParams{URL: u} - err = tmpl.Execute(&builder, l) - if err != nil { - return "", err - } - t := builder.String() - return t, nil -} diff --git a/pkg/auth/email/testdata/invite_user.golden b/pkg/auth/email/testdata/invite_user.golden deleted file mode 100644 index 233d41962ed..00000000000 --- a/pkg/auth/email/testdata/invite_user.golden +++ /dev/null @@ -1,6 +0,0 @@ -Hello,
-You have been invited to join lakeFS
-Browse to lake= -FS user activation page to set up your account
-Thanks
-The lakeFS team
diff --git a/pkg/auth/email/testdata/reset_password.golden b/pkg/auth/email/testdata/reset_password.golden deleted file mode 100644 index 22b5b2efa63..00000000000 --- a/pkg/auth/email/testdata/reset_password.golden +++ /dev/null @@ -1,8 +0,0 @@ -Hello,
-A request has been received to change the password to your account,
-Browse to her= -e to reset your password
-If you did not initiate this request you can please disregard this email. -Thanks
-The lakeFS team
\ No newline at end of file diff --git a/pkg/auth/invite.go b/pkg/auth/invite.go deleted file mode 100644 index 8d2350bda56..00000000000 --- a/pkg/auth/invite.go +++ /dev/null @@ -1,66 +0,0 @@ -package auth - -import ( - "context" - "time" - - "github.com/treeverse/lakefs/pkg/auth/email" - "github.com/treeverse/lakefs/pkg/auth/model" - "github.com/treeverse/lakefs/pkg/logging" -) - -type InviteHandler interface { - InviteUser(ctx context.Context, email string) error - IsInviteSupported() bool -} - -type EmailInviteHandler struct { - svc Service - log logging.Logger - emailer *email.Emailer -} - -func NewEmailInviteHandler(svc Service, log logging.Logger, emailer *email.Emailer) *EmailInviteHandler { - return &EmailInviteHandler{svc: svc, log: log, emailer: emailer} -} - -const ( - DefaultInvitePasswordExpiration = 6 * time.Hour -) - -func (i *EmailInviteHandler) inviteUserRequest(emailAddr string) error { - secret := i.svc.SecretStore().SharedSecret() - currentTime := time.Now() - token, err := GenerateJWTResetPassword(secret, emailAddr, currentTime, currentTime.Add(DefaultInvitePasswordExpiration)) - if err != nil { - return err - } - params := map[string]string{ - "token": token, - "email": emailAddr, - } - err = i.emailer.SendInviteUserEmail([]string{emailAddr}, params) - if err != nil { - return err - } - i.log.WithField("email", emailAddr).Info("invite email sent") - return nil -} - -func (i *EmailInviteHandler) InviteUser(ctx context.Context, email string) error { - u := &model.User{ - CreatedAt: time.Now().UTC(), - Username: email, - Source: "internal", - Email: &email, - } - _, err := i.svc.CreateUser(ctx, u) - if err != nil { - return err - } - return i.inviteUserRequest(email) -} - -func (i *EmailInviteHandler) IsInviteSupported() bool { - return i.emailer != nil && i.emailer.Params.SMTPHost != "" -} diff --git a/pkg/auth/service.go b/pkg/auth/service.go index f9a91bbdd6b..881be111039 100644 --- a/pkg/auth/service.go +++ b/pkg/auth/service.go @@ -20,7 +20,6 @@ import ( "github.com/golang-jwt/jwt/v4" "github.com/rs/xid" "github.com/treeverse/lakefs/pkg/auth/crypt" - "github.com/treeverse/lakefs/pkg/auth/email" "github.com/treeverse/lakefs/pkg/auth/keys" "github.com/treeverse/lakefs/pkg/auth/model" "github.com/treeverse/lakefs/pkg/auth/params" @@ -74,8 +73,6 @@ type CredentialsCreator interface { } type Service interface { - InviteHandler - SecretStore() crypt.SecretStore Cache() Cache @@ -180,10 +177,9 @@ type AuthService struct { secretStore crypt.SecretStore cache Cache log logging.Logger - *EmailInviteHandler } -func NewAuthService(store kv.Store, secretStore crypt.SecretStore, emailer *email.Emailer, cacheConf params.ServiceCache, logger logging.Logger) *AuthService { +func NewAuthService(store kv.Store, secretStore crypt.SecretStore, cacheConf params.ServiceCache, logger logging.Logger) *AuthService { logger.Info("initialized Auth service") var cache Cache if cacheConf.Enabled { @@ -197,7 +193,6 @@ func NewAuthService(store kv.Store, secretStore crypt.SecretStore, emailer *emai cache: cache, log: logger, } - res.EmailInviteHandler = NewEmailInviteHandler(res, logger, emailer) return res } @@ -1141,31 +1136,10 @@ func (s *AuthService) deleteTokens(ctx context.Context) error { } type APIAuthService struct { - apiClient ClientWithResponsesInterface - secretStore crypt.SecretStore - logger logging.Logger - cache Cache - delegatedInviteHandler *EmailInviteHandler -} - -func (a *APIAuthService) InviteUser(ctx context.Context, email string) error { - if a.delegatedInviteHandler != nil { - return a.delegatedInviteHandler.InviteUser(ctx, email) - } - resp, err := a.apiClient.CreateUserWithResponse(ctx, CreateUserJSONRequestBody{ - Email: swag.String(email), - Invite: swag.Bool(true), - Username: email, - }) - if err != nil { - a.logger.WithError(err).Error("failed to create user") - return err - } - return a.validateResponse(resp, http.StatusCreated) -} - -func (a *APIAuthService) IsInviteSupported() bool { - return true + apiClient ClientWithResponsesInterface + secretStore crypt.SecretStore + logger logging.Logger + cache Cache } func (a *APIAuthService) SecretStore() crypt.SecretStore { @@ -1879,7 +1853,7 @@ func (a *APIAuthService) ClaimTokenIDOnce(ctx context.Context, tokenID string, e return a.validateResponse(res, http.StatusCreated) } -func NewAPIAuthService(apiEndpoint, token string, secretStore crypt.SecretStore, cacheConf params.ServiceCache, emailer *email.Emailer, logger logging.Logger) (*APIAuthService, error) { +func NewAPIAuthService(apiEndpoint, token string, secretStore crypt.SecretStore, cacheConf params.ServiceCache, logger logging.Logger) (*APIAuthService, error) { if token == "" { // when no token is provided, generate one. // communicate with auth service always uses a token @@ -1917,9 +1891,6 @@ func NewAPIAuthService(apiEndpoint, token string, secretStore crypt.SecretStore, logger: logger, cache: cache, } - if emailer != nil { - res.delegatedInviteHandler = NewEmailInviteHandler(res, logging.ContextUnavailable(), emailer) - } return res, nil } diff --git a/pkg/auth/service_test.go b/pkg/auth/service_test.go index c9a0d5b3cd3..667e26d1491 100644 --- a/pkg/auth/service_test.go +++ b/pkg/auth/service_test.go @@ -105,7 +105,7 @@ func userWithACLs(t testing.TB, s auth.Service, a model.ACL) string { func TestAuthService_ListUsers_PagedWithPrefix(t *testing.T) { ctx := context.Background() kvStore := kvtest.GetStore(ctx, t) - s := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), nil, authparams.ServiceCache{ + s := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), authparams.ServiceCache{ Enabled: false, }, logging.ContextUnavailable()) @@ -155,7 +155,7 @@ func TestAuthService_ListUsers_PagedWithPrefix(t *testing.T) { func TestAuthService_ListPaged(t *testing.T) { ctx := context.Background() kvStore := kvtest.GetStore(ctx, t) - s := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), nil, authparams.ServiceCache{ + s := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), authparams.ServiceCache{ Enabled: false, }, logging.ContextUnavailable()) @@ -538,16 +538,16 @@ func BenchmarkKVAuthService_ListEffectivePolicies(b *testing.B) { ctx := context.Background() kvStore := kvtest.GetStore(ctx, b) - serviceWithoutCache := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), nil, authparams.ServiceCache{ + serviceWithoutCache := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), authparams.ServiceCache{ Enabled: false, }, logging.ContextUnavailable()) - serviceWithCache := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), nil, authparams.ServiceCache{ + serviceWithCache := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), authparams.ServiceCache{ Enabled: true, Size: 1024, TTL: 20 * time.Second, Jitter: 3 * time.Second, }, logging.ContextUnavailable()) - serviceWithCacheLowTTL := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), nil, authparams.ServiceCache{ + serviceWithCacheLowTTL := auth.NewAuthService(kvStore, crypt.NewSecretStore(someSecret), authparams.ServiceCache{ Enabled: true, Size: 1024, TTL: 1 * time.Millisecond, diff --git a/pkg/auth/testutil/service.go b/pkg/auth/testutil/service.go index 1e35d1fe17a..245645e7fb3 100644 --- a/pkg/auth/testutil/service.go +++ b/pkg/auth/testutil/service.go @@ -15,7 +15,7 @@ import ( func SetupService(t *testing.T, ctx context.Context, secret []byte) (*auth.AuthService, kv.Store) { t.Helper() kvStore := kvtest.GetStore(ctx, t) - return auth.NewAuthService(kvStore, crypt.NewSecretStore(secret), nil, authparams.ServiceCache{ + return auth.NewAuthService(kvStore, crypt.NewSecretStore(secret), authparams.ServiceCache{ Enabled: false, }, logging.ContextUnavailable()), kvStore } diff --git a/pkg/config/config.go b/pkg/config/config.go index ea71caab08f..d9d42bf7eeb 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -190,9 +190,8 @@ type Config struct { SecretKey SecureString `mapstructure:"secret_key" validate:"required"` } `mapstructure:"encrypt"` API struct { - Endpoint string `mapstructure:"endpoint"` - Token SecureString `mapstructure:"token"` - SupportsInvites bool `mapstructure:"supports_invites"` + Endpoint string `mapstructure:"endpoint"` + Token SecureString `mapstructure:"token"` } `mapstructure:"api"` RemoteAuthenticator struct { // Enabled if set true will enable remote authentication diff --git a/pkg/kv/migrations/rbac_to_acl.go b/pkg/kv/migrations/rbac_to_acl.go index c9b63b639d3..8bc49cbb123 100644 --- a/pkg/kv/migrations/rbac_to_acl.go +++ b/pkg/kv/migrations/rbac_to_acl.go @@ -73,7 +73,6 @@ func MigrateToACL(ctx context.Context, kvStore kv.Store, cfg *config.Config, log authService := auth.NewAuthService( kvStore, crypt.NewSecretStore([]byte(cfg.Auth.Encrypt.SecretKey)), - nil, authparams.ServiceCache(cfg.Auth.Cache), logger.WithField("service", "auth_service"), ) diff --git a/pkg/loadtest/local_load_test.go b/pkg/loadtest/local_load_test.go index a1b9797105f..363df8f2e84 100644 --- a/pkg/loadtest/local_load_test.go +++ b/pkg/loadtest/local_load_test.go @@ -13,7 +13,6 @@ import ( "github.com/treeverse/lakefs/pkg/api" "github.com/treeverse/lakefs/pkg/auth" "github.com/treeverse/lakefs/pkg/auth/crypt" - "github.com/treeverse/lakefs/pkg/auth/email" authmodel "github.com/treeverse/lakefs/pkg/auth/model" authparams "github.com/treeverse/lakefs/pkg/auth/params" "github.com/treeverse/lakefs/pkg/auth/setup" @@ -50,7 +49,7 @@ func TestLocalLoad(t *testing.T) { } kvStore := kvtest.GetStore(ctx, t) - authService := auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), nil, authparams.ServiceCache{}, logging.ContextUnavailable().WithField("service", "auth")) + authService := auth.NewAuthService(kvStore, crypt.NewSecretStore([]byte("some secret")), authparams.ServiceCache{}, logging.ContextUnavailable().WithField("service", "auth")) meta := auth.NewKVMetadataManager("local_load_test", conf.Installation.FixedID, conf.Database.Type, kvStore) blockstoreType := os.Getenv(testutil.EnvKeyUseBlockAdapter) @@ -84,9 +83,8 @@ func TestLocalLoad(t *testing.T) { _ = c.Close() }) auditChecker := version.NewDefaultAuditChecker(conf.Security.AuditCheckURL, "", nil) - emailer, err := email.NewEmailer(email.Params(conf.Email)) testutil.Must(t, err) - handler := api.Serve(conf, c, authenticator, authService, blockAdapter, meta, migrator, &stats.NullCollector{}, nil, actionsService, auditChecker, logging.ContextUnavailable(), emailer, nil, nil, upload.DefaultPathProvider, nil) + handler := api.Serve(conf, c, authenticator, authService, blockAdapter, meta, migrator, &stats.NullCollector{}, nil, actionsService, auditChecker, logging.ContextUnavailable(), nil, nil, upload.DefaultPathProvider, nil) ts := httptest.NewServer(handler) defer ts.Close() diff --git a/webui/src/pages/auth/login.tsx b/webui/src/pages/auth/login.tsx index 8e3a999693f..66d5e93b738 100644 --- a/webui/src/pages/auth/login.tsx +++ b/webui/src/pages/auth/login.tsx @@ -39,7 +39,7 @@ const LoginForm = ({loginConfig}: {loginConfig: LoginConfig}) => { } catch(err) { if (err instanceof AuthenticationError && err.status === 401) { const contents = {__html: `${loginConfig.login_failed_message}` || - "Credentials don't match."}; + "Credentials don't match."}; setLoginError(); } } diff --git a/webui/src/pages/auth/users/index.jsx b/webui/src/pages/auth/users/index.jsx index bd81608f110..ae0c0970240 100644 --- a/webui/src/pages/auth/users/index.jsx +++ b/webui/src/pages/auth/users/index.jsx @@ -4,7 +4,7 @@ import {Route, Routes} from "react-router-dom"; import Button from "react-bootstrap/Button"; import {AuthLayout} from "../../../lib/components/auth/layout"; -import {useAPI, useAPIWithPagination} from "../../../lib/hooks/api"; +import {useAPIWithPagination} from "../../../lib/hooks/api"; import {auth} from "../../../lib/api"; import useUser from "../../../lib/hooks/user"; import {ConfirmationButton} from "../../../lib/components/modals"; @@ -23,7 +23,6 @@ import { RefreshButton } from "../../../lib/components/controls"; import UserPage from "./user"; -import validator from "validator/es"; import { disallowPercentSign, INVALID_USER_NAME_ERROR_MESSAGE } from "../validation"; const USER_NOT_FOUND = "unknown"; @@ -39,24 +38,18 @@ const UsersContainer = ({nextPage, refresh, setRefresh, error, loading, userList const [selected, setSelected] = useState([]); const [deleteError, setDeleteError] = useState(null); const [showCreate, setShowCreate] = useState(false); - const [showInvite, setShowInvite] = useState(false); - useEffect(() => { setSelected([]); }, [refresh, after]); - const authCapabilities = useAPI(() => auth.getAuthCapabilities()); if (error) return ; if (loading) return ; - if (authCapabilities.loading) return ; - - const canInviteUsers = !authCapabilities.error && authCapabilities.response && authCapabilities.response.invite_user; return ( <> - setShowInvite(true)} onClickCreate={() => setShowCreate(true)} + setShowCreate(true)} onConfirmDelete={() => { auth.deleteUsers(selected.map(u => u.id)) .catch(err => setDeleteError(err)) @@ -84,29 +77,12 @@ const UsersContainer = ({nextPage, refresh, setRefresh, error, loading, userList setRefresh(!refresh); }); }} - title={canInviteUsers ? "Create Integration User" : "Create User"} - placeholder={canInviteUsers ? "Integration Name (e.g. Spark)" : "Username (e.g. 'jane.doe')"} + title={"Create Integration User"} + placeholder={"Integration Name (e.g. Spark)"} actionName={"Create"} validationFunction={disallowPercentSign(INVALID_USER_NAME_ERROR_MESSAGE)} /> - setShowInvite(false)} - onAction={async (userEmail) => { - if (!validator.isEmail(userEmail)) { - throw new Error("Invalid email address"); - } - await auth.createUser(userEmail, true); - setSelected([]); - setShowInvite(false); - setRefresh(!refresh); - }} - title={"Invite User"} - placeholder={"Email"} - actionName={"Invite"} - /> - { +const UserActionsActionGroup = ({selected, onClickCreate, onConfirmDelete }) => { return ( - -