From a81657f0a56365da7129b381ef6262fd531f7067 Mon Sep 17 00:00:00 2001 From: guy-har <60321938+guy-har@users.noreply.github.com> Date: Wed, 3 Apr 2024 10:20:46 +0300 Subject: [PATCH] Add TTL to STS (#7605) --- api/swagger.yml | 8 +++- clients/java-legacy/README.md | 2 +- clients/java-legacy/api/openapi.yaml | 9 +++- clients/java-legacy/docs/ExperimentalApi.md | 12 ++--- clients/java-legacy/docs/StsAuthRequest.md | 1 + .../lakefs/clients/api/ExperimentalApi.java | 22 +++++----- .../clients/api/model/StsAuthRequest.java | 33 +++++++++++++- .../clients/api/ExperimentalApiTest.java | 4 +- .../clients/api/model/StsAuthRequestTest.java | 8 ++++ clients/java/README.md | 2 +- clients/java/api/openapi.yaml | 9 +++- clients/java/docs/ExperimentalApi.md | 12 ++--- clients/java/docs/StsAuthRequest.md | 1 + .../lakefs/clients/sdk/ExperimentalApi.java | 42 +++++++++--------- .../clients/sdk/model/StsAuthRequest.java | 32 +++++++++++++- .../clients/sdk/ExperimentalApiTest.java | 4 +- .../clients/sdk/model/StsAuthRequestTest.java | 8 ++++ clients/python-legacy/README.md | 2 +- clients/python-legacy/docs/ExperimentalApi.md | 11 ++--- clients/python-legacy/docs/StsAuthRequest.md | 1 + .../lakefs_client/api/experimental_api.py | 10 ++--- .../lakefs_client/model/sts_auth_request.py | 4 ++ .../test/test_experimental_api.py | 4 +- clients/python/README.md | 2 +- clients/python/docs/ExperimentalApi.md | 12 ++--- clients/python/docs/StsAuthRequest.md | 1 + .../python/lakefs_sdk/api/experimental_api.py | 14 +++--- .../lakefs_sdk/models/sts_auth_request.py | 10 +++-- clients/python/test/test_experimental_api.py | 4 +- clients/python/test/test_sts_auth_request.py | 3 +- docs/assets/js/swagger.yml | 8 +++- pkg/api/auth_middleware_test.go | 2 +- pkg/api/controller.go | 28 +++++++++--- pkg/api/controller_test.go | 2 +- pkg/api/jwt_login.go | 8 ++-- pkg/authentication/errors.go | 1 - pkg/authentication/service.go | 36 +++++---------- pkg/authentication/service_test.go | 44 +++++-------------- 38 files changed, 252 insertions(+), 164 deletions(-) diff --git a/api/swagger.yml b/api/swagger.yml index 9f14917492c..f074dfa38fe 100644 --- a/api/swagger.yml +++ b/api/swagger.yml @@ -1062,6 +1062,12 @@ components: type: string redirect_uri: type: string + ttl_seconds: + type: integer + format: int64 + description: | + The time-to-live for the generated token in seconds. The maximum + value is 3600 seconds (1 hour) max is 12 hours. AuthenticationToken: type: object required: @@ -1818,7 +1824,7 @@ paths: post: tags: - experimental - operationId: STSLogin + operationId: stsLogin # change to stsLogin summary: perform a login with STS security: [] requestBody: diff --git a/clients/java-legacy/README.md b/clients/java-legacy/README.md index 892b5720a27..cfaf83be69c 100644 --- a/clients/java-legacy/README.md +++ b/clients/java-legacy/README.md @@ -193,7 +193,7 @@ Class | Method | HTTP request | Description *ExperimentalApi* | [**getExternalPrincipal**](docs/ExperimentalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id *ExperimentalApi* | [**hardResetBranch**](docs/ExperimentalApi.md#hardResetBranch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch *ExperimentalApi* | [**listUserExternalPrincipals**](docs/ExperimentalApi.md#listUserExternalPrincipals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user -*ExperimentalApi* | [**sTSLogin**](docs/ExperimentalApi.md#sTSLogin) | **POST** /sts/login | perform a login with STS +*ExperimentalApi* | [**stsLogin**](docs/ExperimentalApi.md#stsLogin) | **POST** /sts/login | perform a login with STS *ExternalApi* | [**createUserExternalPrincipal**](docs/ExternalApi.md#createUserExternalPrincipal) | **POST** /auth/users/{userId}/external/principals | attach external principal to user *ExternalApi* | [**deleteUserExternalPrincipal**](docs/ExternalApi.md#deleteUserExternalPrincipal) | **DELETE** /auth/users/{userId}/external/principals | delete external principal from user *ExternalApi* | [**getExternalPrincipal**](docs/ExternalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id diff --git a/clients/java-legacy/api/openapi.yaml b/clients/java-legacy/api/openapi.yaml index 0e6f4b1353d..16ef31f0d8c 100644 --- a/clients/java-legacy/api/openapi.yaml +++ b/clients/java-legacy/api/openapi.yaml @@ -176,7 +176,7 @@ paths: x-accepts: application/json /sts/login: post: - operationId: STSLogin + operationId: stsLogin requestBody: content: application/json: @@ -8177,6 +8177,7 @@ components: StsAuthRequest: example: code: code + ttl_seconds: 0 state: state redirect_uri: redirect_uri properties: @@ -8186,6 +8187,12 @@ components: type: string redirect_uri: type: string + ttl_seconds: + description: | + The time-to-live for the generated token in seconds. The maximum + value is 3600 seconds (1 hour) max is 12 hours. + format: int64 + type: integer required: - code - redirect_uri diff --git a/clients/java-legacy/docs/ExperimentalApi.md b/clients/java-legacy/docs/ExperimentalApi.md index 4751281d350..e79d83e9f85 100644 --- a/clients/java-legacy/docs/ExperimentalApi.md +++ b/clients/java-legacy/docs/ExperimentalApi.md @@ -12,7 +12,7 @@ Method | HTTP request | Description [**getExternalPrincipal**](ExperimentalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id [**hardResetBranch**](ExperimentalApi.md#hardResetBranch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch [**listUserExternalPrincipals**](ExperimentalApi.md#listUserExternalPrincipals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user -[**sTSLogin**](ExperimentalApi.md#sTSLogin) | **POST** /sts/login | perform a login with STS +[**stsLogin**](ExperimentalApi.md#stsLogin) | **POST** /sts/login | perform a login with STS @@ -802,9 +802,9 @@ Name | Type | Description | Notes **420** | too many requests | - | **0** | Internal Server Error | - | - -# **sTSLogin** -> AuthenticationToken sTSLogin(stsAuthRequest) + +# **stsLogin** +> AuthenticationToken stsLogin(stsAuthRequest) perform a login with STS @@ -825,10 +825,10 @@ public class Example { ExperimentalApi apiInstance = new ExperimentalApi(defaultClient); StsAuthRequest stsAuthRequest = new StsAuthRequest(); // StsAuthRequest | try { - AuthenticationToken result = apiInstance.sTSLogin(stsAuthRequest); + AuthenticationToken result = apiInstance.stsLogin(stsAuthRequest); System.out.println(result); } catch (ApiException e) { - System.err.println("Exception when calling ExperimentalApi#sTSLogin"); + System.err.println("Exception when calling ExperimentalApi#stsLogin"); System.err.println("Status code: " + e.getCode()); System.err.println("Reason: " + e.getResponseBody()); System.err.println("Response headers: " + e.getResponseHeaders()); diff --git a/clients/java-legacy/docs/StsAuthRequest.md b/clients/java-legacy/docs/StsAuthRequest.md index 8e90c32b39d..ee58c5376c9 100644 --- a/clients/java-legacy/docs/StsAuthRequest.md +++ b/clients/java-legacy/docs/StsAuthRequest.md @@ -10,6 +10,7 @@ Name | Type | Description | Notes **code** | **String** | | **state** | **String** | | **redirectUri** | **String** | | +**ttlSeconds** | **Long** | The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. | [optional] diff --git a/clients/java-legacy/src/main/java/io/lakefs/clients/api/ExperimentalApi.java b/clients/java-legacy/src/main/java/io/lakefs/clients/api/ExperimentalApi.java index b0e1f1783e7..3a2090dfa73 100644 --- a/clients/java-legacy/src/main/java/io/lakefs/clients/api/ExperimentalApi.java +++ b/clients/java-legacy/src/main/java/io/lakefs/clients/api/ExperimentalApi.java @@ -1294,7 +1294,7 @@ public okhttp3.Call listUserExternalPrincipalsAsync(String userId, String prefix return localVarCall; } /** - * Build call for sTSLogin + * Build call for stsLogin * @param stsAuthRequest (required) * @param _callback Callback for upload/download progress * @return Call to execute @@ -1307,7 +1307,7 @@ public okhttp3.Call listUserExternalPrincipalsAsync(String userId, String prefix 0 Internal Server Error - */ - public okhttp3.Call sTSLoginCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { + public okhttp3.Call stsLoginCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { Object localVarPostBody = stsAuthRequest; // create path and map variables @@ -1338,15 +1338,15 @@ public okhttp3.Call sTSLoginCall(StsAuthRequest stsAuthRequest, final ApiCallbac } @SuppressWarnings("rawtypes") - private okhttp3.Call sTSLoginValidateBeforeCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { + private okhttp3.Call stsLoginValidateBeforeCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { // verify the required parameter 'stsAuthRequest' is set if (stsAuthRequest == null) { - throw new ApiException("Missing the required parameter 'stsAuthRequest' when calling sTSLogin(Async)"); + throw new ApiException("Missing the required parameter 'stsAuthRequest' when calling stsLogin(Async)"); } - okhttp3.Call localVarCall = sTSLoginCall(stsAuthRequest, _callback); + okhttp3.Call localVarCall = stsLoginCall(stsAuthRequest, _callback); return localVarCall; } @@ -1365,8 +1365,8 @@ private okhttp3.Call sTSLoginValidateBeforeCall(StsAuthRequest stsAuthRequest, f 0 Internal Server Error - */ - public AuthenticationToken sTSLogin(StsAuthRequest stsAuthRequest) throws ApiException { - ApiResponse localVarResp = sTSLoginWithHttpInfo(stsAuthRequest); + public AuthenticationToken stsLogin(StsAuthRequest stsAuthRequest) throws ApiException { + ApiResponse localVarResp = stsLoginWithHttpInfo(stsAuthRequest); return localVarResp.getData(); } @@ -1384,8 +1384,8 @@ public AuthenticationToken sTSLogin(StsAuthRequest stsAuthRequest) throws ApiExc 0 Internal Server Error - */ - public ApiResponse sTSLoginWithHttpInfo(StsAuthRequest stsAuthRequest) throws ApiException { - okhttp3.Call localVarCall = sTSLoginValidateBeforeCall(stsAuthRequest, null); + public ApiResponse stsLoginWithHttpInfo(StsAuthRequest stsAuthRequest) throws ApiException { + okhttp3.Call localVarCall = stsLoginValidateBeforeCall(stsAuthRequest, null); Type localVarReturnType = new TypeToken(){}.getType(); return localVarApiClient.execute(localVarCall, localVarReturnType); } @@ -1405,9 +1405,9 @@ public ApiResponse sTSLoginWithHttpInfo(StsAuthRequest stsA 0 Internal Server Error - */ - public okhttp3.Call sTSLoginAsync(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { + public okhttp3.Call stsLoginAsync(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { - okhttp3.Call localVarCall = sTSLoginValidateBeforeCall(stsAuthRequest, _callback); + okhttp3.Call localVarCall = stsLoginValidateBeforeCall(stsAuthRequest, _callback); Type localVarReturnType = new TypeToken(){}.getType(); localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); return localVarCall; diff --git a/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/StsAuthRequest.java b/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/StsAuthRequest.java index 0d07397f244..18be384d5c5 100644 --- a/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/StsAuthRequest.java +++ b/clients/java-legacy/src/main/java/io/lakefs/clients/api/model/StsAuthRequest.java @@ -41,6 +41,10 @@ public class StsAuthRequest { @SerializedName(SERIALIZED_NAME_REDIRECT_URI) private String redirectUri; + public static final String SERIALIZED_NAME_TTL_SECONDS = "ttl_seconds"; + @SerializedName(SERIALIZED_NAME_TTL_SECONDS) + private Long ttlSeconds; + public StsAuthRequest code(String code) { @@ -111,6 +115,29 @@ public void setRedirectUri(String redirectUri) { } + public StsAuthRequest ttlSeconds(Long ttlSeconds) { + + this.ttlSeconds = ttlSeconds; + return this; + } + + /** + * The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. + * @return ttlSeconds + **/ + @javax.annotation.Nullable + @ApiModelProperty(value = "The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. ") + + public Long getTtlSeconds() { + return ttlSeconds; + } + + + public void setTtlSeconds(Long ttlSeconds) { + this.ttlSeconds = ttlSeconds; + } + + @Override public boolean equals(Object o) { if (this == o) { @@ -122,12 +149,13 @@ public boolean equals(Object o) { StsAuthRequest stsAuthRequest = (StsAuthRequest) o; return Objects.equals(this.code, stsAuthRequest.code) && Objects.equals(this.state, stsAuthRequest.state) && - Objects.equals(this.redirectUri, stsAuthRequest.redirectUri); + Objects.equals(this.redirectUri, stsAuthRequest.redirectUri) && + Objects.equals(this.ttlSeconds, stsAuthRequest.ttlSeconds); } @Override public int hashCode() { - return Objects.hash(code, state, redirectUri); + return Objects.hash(code, state, redirectUri, ttlSeconds); } @Override @@ -137,6 +165,7 @@ public String toString() { sb.append(" code: ").append(toIndentedString(code)).append("\n"); sb.append(" state: ").append(toIndentedString(state)).append("\n"); sb.append(" redirectUri: ").append(toIndentedString(redirectUri)).append("\n"); + sb.append(" ttlSeconds: ").append(toIndentedString(ttlSeconds)).append("\n"); sb.append("}"); return sb.toString(); } diff --git a/clients/java-legacy/src/test/java/io/lakefs/clients/api/ExperimentalApiTest.java b/clients/java-legacy/src/test/java/io/lakefs/clients/api/ExperimentalApiTest.java index b0d16b23225..b293da228d0 100644 --- a/clients/java-legacy/src/test/java/io/lakefs/clients/api/ExperimentalApiTest.java +++ b/clients/java-legacy/src/test/java/io/lakefs/clients/api/ExperimentalApiTest.java @@ -191,9 +191,9 @@ public void listUserExternalPrincipalsTest() throws ApiException { * if the Api call fails */ @Test - public void sTSLoginTest() throws ApiException { + public void stsLoginTest() throws ApiException { StsAuthRequest stsAuthRequest = null; - AuthenticationToken response = api.sTSLogin(stsAuthRequest); + AuthenticationToken response = api.stsLogin(stsAuthRequest); // TODO: test validations } diff --git a/clients/java-legacy/src/test/java/io/lakefs/clients/api/model/StsAuthRequestTest.java b/clients/java-legacy/src/test/java/io/lakefs/clients/api/model/StsAuthRequestTest.java index 4f5ef499f4b..117b06bf52c 100644 --- a/clients/java-legacy/src/test/java/io/lakefs/clients/api/model/StsAuthRequestTest.java +++ b/clients/java-legacy/src/test/java/io/lakefs/clients/api/model/StsAuthRequestTest.java @@ -64,4 +64,12 @@ public void redirectUriTest() { // TODO: test redirectUri } + /** + * Test the property 'ttlSeconds' + */ + @Test + public void ttlSecondsTest() { + // TODO: test ttlSeconds + } + } diff --git a/clients/java/README.md b/clients/java/README.md index 9c434f70823..205c95be9db 100644 --- a/clients/java/README.md +++ b/clients/java/README.md @@ -201,7 +201,7 @@ Class | Method | HTTP request | Description *ExperimentalApi* | [**getExternalPrincipal**](docs/ExperimentalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id *ExperimentalApi* | [**hardResetBranch**](docs/ExperimentalApi.md#hardResetBranch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch *ExperimentalApi* | [**listUserExternalPrincipals**](docs/ExperimentalApi.md#listUserExternalPrincipals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user -*ExperimentalApi* | [**sTSLogin**](docs/ExperimentalApi.md#sTSLogin) | **POST** /sts/login | perform a login with STS +*ExperimentalApi* | [**stsLogin**](docs/ExperimentalApi.md#stsLogin) | **POST** /sts/login | perform a login with STS *ExternalApi* | [**createUserExternalPrincipal**](docs/ExternalApi.md#createUserExternalPrincipal) | **POST** /auth/users/{userId}/external/principals | attach external principal to user *ExternalApi* | [**deleteUserExternalPrincipal**](docs/ExternalApi.md#deleteUserExternalPrincipal) | **DELETE** /auth/users/{userId}/external/principals | delete external principal from user *ExternalApi* | [**getExternalPrincipal**](docs/ExternalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id diff --git a/clients/java/api/openapi.yaml b/clients/java/api/openapi.yaml index 1d762955532..195ab74d731 100644 --- a/clients/java/api/openapi.yaml +++ b/clients/java/api/openapi.yaml @@ -176,7 +176,7 @@ paths: x-accepts: application/json /sts/login: post: - operationId: STSLogin + operationId: stsLogin requestBody: content: application/json: @@ -8151,6 +8151,7 @@ components: StsAuthRequest: example: code: code + ttl_seconds: 0 state: state redirect_uri: redirect_uri properties: @@ -8160,6 +8161,12 @@ components: type: string redirect_uri: type: string + ttl_seconds: + description: | + The time-to-live for the generated token in seconds. The maximum + value is 3600 seconds (1 hour) max is 12 hours. + format: int64 + type: integer required: - code - redirect_uri diff --git a/clients/java/docs/ExperimentalApi.md b/clients/java/docs/ExperimentalApi.md index a04e38c9a48..e9fbde14aa1 100644 --- a/clients/java/docs/ExperimentalApi.md +++ b/clients/java/docs/ExperimentalApi.md @@ -12,7 +12,7 @@ All URIs are relative to */api/v1* | [**getExternalPrincipal**](ExperimentalApi.md#getExternalPrincipal) | **GET** /auth/external/principals | describe external principal by id | | [**hardResetBranch**](ExperimentalApi.md#hardResetBranch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch | | [**listUserExternalPrincipals**](ExperimentalApi.md#listUserExternalPrincipals) | **GET** /auth/users/{userId}/external/principals/ls | list user external policies attached to a user | -| [**sTSLogin**](ExperimentalApi.md#sTSLogin) | **POST** /sts/login | perform a login with STS | +| [**stsLogin**](ExperimentalApi.md#stsLogin) | **POST** /sts/login | perform a login with STS | @@ -818,9 +818,9 @@ public class Example { | **420** | too many requests | - | | **0** | Internal Server Error | - | - -# **sTSLogin** -> AuthenticationToken sTSLogin(stsAuthRequest).execute(); + +# **stsLogin** +> AuthenticationToken stsLogin(stsAuthRequest).execute(); perform a login with STS @@ -841,11 +841,11 @@ public class Example { ExperimentalApi apiInstance = new ExperimentalApi(defaultClient); StsAuthRequest stsAuthRequest = new StsAuthRequest(); // StsAuthRequest | try { - AuthenticationToken result = apiInstance.sTSLogin(stsAuthRequest) + AuthenticationToken result = apiInstance.stsLogin(stsAuthRequest) .execute(); System.out.println(result); } catch (ApiException e) { - System.err.println("Exception when calling ExperimentalApi#sTSLogin"); + System.err.println("Exception when calling ExperimentalApi#stsLogin"); System.err.println("Status code: " + e.getCode()); System.err.println("Reason: " + e.getResponseBody()); System.err.println("Response headers: " + e.getResponseHeaders()); diff --git a/clients/java/docs/StsAuthRequest.md b/clients/java/docs/StsAuthRequest.md index 0f87c33873e..bf1683b4810 100644 --- a/clients/java/docs/StsAuthRequest.md +++ b/clients/java/docs/StsAuthRequest.md @@ -10,6 +10,7 @@ |**code** | **String** | | | |**state** | **String** | | | |**redirectUri** | **String** | | | +|**ttlSeconds** | **Long** | The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. | [optional] | 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 21fac8fdb74..05975496091 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 @@ -1717,7 +1717,7 @@ public okhttp3.Call executeAsync(final ApiCallback _callb public APIlistUserExternalPrincipalsRequest listUserExternalPrincipals(String userId) { return new APIlistUserExternalPrincipalsRequest(userId); } - private okhttp3.Call sTSLoginCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { + private okhttp3.Call stsLoginCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { String basePath = null; // Operation Servers String[] localBasePaths = new String[] { }; @@ -1763,40 +1763,40 @@ private okhttp3.Call sTSLoginCall(StsAuthRequest stsAuthRequest, final ApiCallba } @SuppressWarnings("rawtypes") - private okhttp3.Call sTSLoginValidateBeforeCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { + private okhttp3.Call stsLoginValidateBeforeCall(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { // verify the required parameter 'stsAuthRequest' is set if (stsAuthRequest == null) { - throw new ApiException("Missing the required parameter 'stsAuthRequest' when calling sTSLogin(Async)"); + throw new ApiException("Missing the required parameter 'stsAuthRequest' when calling stsLogin(Async)"); } - return sTSLoginCall(stsAuthRequest, _callback); + return stsLoginCall(stsAuthRequest, _callback); } - private ApiResponse sTSLoginWithHttpInfo(StsAuthRequest stsAuthRequest) throws ApiException { - okhttp3.Call localVarCall = sTSLoginValidateBeforeCall(stsAuthRequest, null); + private ApiResponse stsLoginWithHttpInfo(StsAuthRequest stsAuthRequest) throws ApiException { + okhttp3.Call localVarCall = stsLoginValidateBeforeCall(stsAuthRequest, null); Type localVarReturnType = new TypeToken(){}.getType(); return localVarApiClient.execute(localVarCall, localVarReturnType); } - private okhttp3.Call sTSLoginAsync(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { + private okhttp3.Call stsLoginAsync(StsAuthRequest stsAuthRequest, final ApiCallback _callback) throws ApiException { - okhttp3.Call localVarCall = sTSLoginValidateBeforeCall(stsAuthRequest, _callback); + okhttp3.Call localVarCall = stsLoginValidateBeforeCall(stsAuthRequest, _callback); Type localVarReturnType = new TypeToken(){}.getType(); localVarApiClient.executeAsync(localVarCall, localVarReturnType, _callback); return localVarCall; } - public class APIsTSLoginRequest { + public class APIstsLoginRequest { private final StsAuthRequest stsAuthRequest; - private APIsTSLoginRequest(StsAuthRequest stsAuthRequest) { + private APIstsLoginRequest(StsAuthRequest stsAuthRequest) { this.stsAuthRequest = stsAuthRequest; } /** - * Build call for sTSLogin + * Build call for stsLogin * @param _callback ApiCallback API callback * @return Call to execute * @throws ApiException If fail to serialize the request body object @@ -1809,11 +1809,11 @@ private APIsTSLoginRequest(StsAuthRequest stsAuthRequest) { */ public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { - return sTSLoginCall(stsAuthRequest, _callback); + return stsLoginCall(stsAuthRequest, _callback); } /** - * Execute sTSLogin request + * Execute stsLogin request * @return AuthenticationToken * @throws ApiException If fail to call the API, e.g. server error or cannot deserialize the response body * @http.response.details @@ -1825,12 +1825,12 @@ public okhttp3.Call buildCall(final ApiCallback _callback) throws ApiException { */ public AuthenticationToken execute() throws ApiException { - ApiResponse localVarResp = sTSLoginWithHttpInfo(stsAuthRequest); + ApiResponse localVarResp = stsLoginWithHttpInfo(stsAuthRequest); return localVarResp.getData(); } /** - * Execute sTSLogin request with HTTP info returned + * Execute stsLogin 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 @@ -1842,11 +1842,11 @@ public AuthenticationToken execute() throws ApiException { */ public ApiResponse executeWithHttpInfo() throws ApiException { - return sTSLoginWithHttpInfo(stsAuthRequest); + return stsLoginWithHttpInfo(stsAuthRequest); } /** - * Execute sTSLogin request (asynchronously) + * Execute stsLogin 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 @@ -1859,7 +1859,7 @@ public ApiResponse executeWithHttpInfo() throws ApiExceptio */ public okhttp3.Call executeAsync(final ApiCallback _callback) throws ApiException { - return sTSLoginAsync(stsAuthRequest, _callback); + return stsLoginAsync(stsAuthRequest, _callback); } } @@ -1867,7 +1867,7 @@ public okhttp3.Call executeAsync(final ApiCallback _callbac * perform a login with STS * * @param stsAuthRequest (required) - * @return APIsTSLoginRequest + * @return APIstsLoginRequest * @http.response.details @@ -1876,7 +1876,7 @@ public okhttp3.Call executeAsync(final ApiCallback _callbac
Status Code Description Response Headers
0 Internal Server Error -
*/ - public APIsTSLoginRequest sTSLogin(StsAuthRequest stsAuthRequest) { - return new APIsTSLoginRequest(stsAuthRequest); + public APIstsLoginRequest stsLogin(StsAuthRequest stsAuthRequest) { + return new APIstsLoginRequest(stsAuthRequest); } } diff --git a/clients/java/src/main/java/io/lakefs/clients/sdk/model/StsAuthRequest.java b/clients/java/src/main/java/io/lakefs/clients/sdk/model/StsAuthRequest.java index aee35d8e15e..5d6bd245e2c 100644 --- a/clients/java/src/main/java/io/lakefs/clients/sdk/model/StsAuthRequest.java +++ b/clients/java/src/main/java/io/lakefs/clients/sdk/model/StsAuthRequest.java @@ -64,6 +64,10 @@ public class StsAuthRequest { @SerializedName(SERIALIZED_NAME_REDIRECT_URI) private String redirectUri; + public static final String SERIALIZED_NAME_TTL_SECONDS = "ttl_seconds"; + @SerializedName(SERIALIZED_NAME_TTL_SECONDS) + private Long ttlSeconds; + public StsAuthRequest() { } @@ -129,6 +133,27 @@ public void setRedirectUri(String redirectUri) { this.redirectUri = redirectUri; } + + public StsAuthRequest ttlSeconds(Long ttlSeconds) { + + this.ttlSeconds = ttlSeconds; + return this; + } + + /** + * The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. + * @return ttlSeconds + **/ + @javax.annotation.Nullable + public Long getTtlSeconds() { + return ttlSeconds; + } + + + public void setTtlSeconds(Long ttlSeconds) { + this.ttlSeconds = ttlSeconds; + } + /** * A container for additional, undeclared properties. * This is a holder for any undeclared properties as specified with @@ -186,13 +211,14 @@ public boolean equals(Object o) { StsAuthRequest stsAuthRequest = (StsAuthRequest) o; return Objects.equals(this.code, stsAuthRequest.code) && Objects.equals(this.state, stsAuthRequest.state) && - Objects.equals(this.redirectUri, stsAuthRequest.redirectUri)&& + Objects.equals(this.redirectUri, stsAuthRequest.redirectUri) && + Objects.equals(this.ttlSeconds, stsAuthRequest.ttlSeconds)&& Objects.equals(this.additionalProperties, stsAuthRequest.additionalProperties); } @Override public int hashCode() { - return Objects.hash(code, state, redirectUri, additionalProperties); + return Objects.hash(code, state, redirectUri, ttlSeconds, additionalProperties); } @Override @@ -202,6 +228,7 @@ public String toString() { sb.append(" code: ").append(toIndentedString(code)).append("\n"); sb.append(" state: ").append(toIndentedString(state)).append("\n"); sb.append(" redirectUri: ").append(toIndentedString(redirectUri)).append("\n"); + sb.append(" ttlSeconds: ").append(toIndentedString(ttlSeconds)).append("\n"); sb.append(" additionalProperties: ").append(toIndentedString(additionalProperties)).append("\n"); sb.append("}"); return sb.toString(); @@ -228,6 +255,7 @@ private String toIndentedString(Object o) { openapiFields.add("code"); openapiFields.add("state"); openapiFields.add("redirect_uri"); + openapiFields.add("ttl_seconds"); // a set of required properties/fields (JSON key names) openapiRequiredFields = new HashSet(); 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 05e4f62cda0..5f95e34cc4d 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 @@ -187,9 +187,9 @@ public void listUserExternalPrincipalsTest() throws ApiException { * @throws ApiException if the Api call fails */ @Test - public void sTSLoginTest() throws ApiException { + public void stsLoginTest() throws ApiException { StsAuthRequest stsAuthRequest = null; - AuthenticationToken response = api.sTSLogin(stsAuthRequest) + AuthenticationToken response = api.stsLogin(stsAuthRequest) .execute(); // TODO: test validations } diff --git a/clients/java/src/test/java/io/lakefs/clients/sdk/model/StsAuthRequestTest.java b/clients/java/src/test/java/io/lakefs/clients/sdk/model/StsAuthRequestTest.java index c5db5e80298..ad92f07135a 100644 --- a/clients/java/src/test/java/io/lakefs/clients/sdk/model/StsAuthRequestTest.java +++ b/clients/java/src/test/java/io/lakefs/clients/sdk/model/StsAuthRequestTest.java @@ -61,4 +61,12 @@ public void redirectUriTest() { // TODO: test redirectUri } + /** + * Test the property 'ttlSeconds' + */ + @Test + public void ttlSecondsTest() { + // TODO: test ttlSeconds + } + } diff --git a/clients/python-legacy/README.md b/clients/python-legacy/README.md index d173c981bf3..844fa24d27b 100644 --- a/clients/python-legacy/README.md +++ b/clients/python-legacy/README.md @@ -174,7 +174,7 @@ 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* | [**hard_reset_branch**](docs/ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch *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* | [**s_ts_login**](docs/ExperimentalApi.md#s_ts_login) | **POST** /sts/login | perform a login with STS +*ExperimentalApi* | [**sts_login**](docs/ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS *ExternalApi* | [**create_user_external_principal**](docs/ExternalApi.md#create_user_external_principal) | **POST** /auth/users/{userId}/external/principals | attach external principal to user *ExternalApi* | [**delete_user_external_principal**](docs/ExternalApi.md#delete_user_external_principal) | **DELETE** /auth/users/{userId}/external/principals | delete external principal from user *ExternalApi* | [**get_external_principal**](docs/ExternalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id diff --git a/clients/python-legacy/docs/ExperimentalApi.md b/clients/python-legacy/docs/ExperimentalApi.md index 43e1d31b44d..4f24b30f6e0 100644 --- a/clients/python-legacy/docs/ExperimentalApi.md +++ b/clients/python-legacy/docs/ExperimentalApi.md @@ -12,7 +12,7 @@ Method | HTTP request | Description [**get_external_principal**](ExperimentalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id [**hard_reset_branch**](ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch [**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 -[**s_ts_login**](ExperimentalApi.md#s_ts_login) | **POST** /sts/login | perform a login with STS +[**sts_login**](ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS # **abort_presign_multipart_upload** @@ -1001,8 +1001,8 @@ 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) -# **s_ts_login** -> AuthenticationToken s_ts_login(sts_auth_request) +# **sts_login** +> AuthenticationToken sts_login(sts_auth_request) perform a login with STS @@ -1032,15 +1032,16 @@ with lakefs_client.ApiClient() as api_client: code="code_example", state="state_example", redirect_uri="redirect_uri_example", + ttl_seconds=1, ) # StsAuthRequest | # example passing only required values which don't have defaults set try: # perform a login with STS - api_response = api_instance.s_ts_login(sts_auth_request) + api_response = api_instance.sts_login(sts_auth_request) pprint(api_response) except lakefs_client.ApiException as e: - print("Exception when calling ExperimentalApi->s_ts_login: %s\n" % e) + print("Exception when calling ExperimentalApi->sts_login: %s\n" % e) ``` diff --git a/clients/python-legacy/docs/StsAuthRequest.md b/clients/python-legacy/docs/StsAuthRequest.md index 231c7551555..c21cd844ee1 100644 --- a/clients/python-legacy/docs/StsAuthRequest.md +++ b/clients/python-legacy/docs/StsAuthRequest.md @@ -7,6 +7,7 @@ Name | Type | Description | Notes **code** | **str** | | **state** | **str** | | **redirect_uri** | **str** | | +**ttl_seconds** | **int** | The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. | [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-legacy/lakefs_client/api/experimental_api.py b/clients/python-legacy/lakefs_client/api/experimental_api.py index 38405cf2efc..2a1131527d8 100644 --- a/clients/python-legacy/lakefs_client/api/experimental_api.py +++ b/clients/python-legacy/lakefs_client/api/experimental_api.py @@ -607,12 +607,12 @@ def __init__(self, api_client=None): }, api_client=api_client ) - self.s_ts_login_endpoint = _Endpoint( + self.sts_login_endpoint = _Endpoint( settings={ 'response_type': (AuthenticationToken,), 'auth': [], 'endpoint_path': '/sts/login', - 'operation_id': 's_ts_login', + 'operation_id': 'sts_login', 'http_method': 'POST', 'servers': None, }, @@ -1238,7 +1238,7 @@ def list_user_external_principals( user_id return self.list_user_external_principals_endpoint.call_with_http_info(**kwargs) - def s_ts_login( + def sts_login( self, sts_auth_request, **kwargs @@ -1248,7 +1248,7 @@ def s_ts_login( This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.s_ts_login(sts_auth_request, async_req=True) + >>> thread = api.sts_login(sts_auth_request, async_req=True) >>> result = thread.get() Args: @@ -1301,5 +1301,5 @@ def s_ts_login( kwargs['_host_index'] = kwargs.get('_host_index') kwargs['sts_auth_request'] = \ sts_auth_request - return self.s_ts_login_endpoint.call_with_http_info(**kwargs) + return self.sts_login_endpoint.call_with_http_info(**kwargs) diff --git a/clients/python-legacy/lakefs_client/model/sts_auth_request.py b/clients/python-legacy/lakefs_client/model/sts_auth_request.py index efeba964728..6cea53cffc8 100644 --- a/clients/python-legacy/lakefs_client/model/sts_auth_request.py +++ b/clients/python-legacy/lakefs_client/model/sts_auth_request.py @@ -85,6 +85,7 @@ def openapi_types(): 'code': (str,), # noqa: E501 'state': (str,), # noqa: E501 'redirect_uri': (str,), # noqa: E501 + 'ttl_seconds': (int,), # noqa: E501 } @cached_property @@ -96,6 +97,7 @@ def discriminator(): 'code': 'code', # noqa: E501 'state': 'state', # noqa: E501 'redirect_uri': 'redirect_uri', # noqa: E501 + 'ttl_seconds': 'ttl_seconds', # noqa: E501 } read_only_vars = { @@ -144,6 +146,7 @@ def _from_openapi_data(cls, code, state, redirect_uri, *args, **kwargs): # noqa Animal class but this time we won't travel through its discriminator because we passed in _visited_composed_classes = (Animal,) + ttl_seconds (int): The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. . [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) @@ -233,6 +236,7 @@ def __init__(self, code, state, redirect_uri, *args, **kwargs): # noqa: E501 Animal class but this time we won't travel through its discriminator because we passed in _visited_composed_classes = (Animal,) + ttl_seconds (int): The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. . [optional] # noqa: E501 """ _check_type = kwargs.pop('_check_type', True) diff --git a/clients/python-legacy/test/test_experimental_api.py b/clients/python-legacy/test/test_experimental_api.py index deccd3b4901..3337a175af2 100644 --- a/clients/python-legacy/test/test_experimental_api.py +++ b/clients/python-legacy/test/test_experimental_api.py @@ -80,8 +80,8 @@ def test_list_user_external_principals(self): """ pass - def test_s_ts_login(self): - """Test case for s_ts_login + def test_sts_login(self): + """Test case for sts_login perform a login with STS # noqa: E501 """ diff --git a/clients/python/README.md b/clients/python/README.md index f40b969d642..74a7df8ae9e 100644 --- a/clients/python/README.md +++ b/clients/python/README.md @@ -177,7 +177,7 @@ 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* | [**hard_reset_branch**](docs/ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch *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* | [**s_ts_login**](docs/ExperimentalApi.md#s_ts_login) | **POST** /sts/login | perform a login with STS +*ExperimentalApi* | [**sts_login**](docs/ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS *ExternalApi* | [**create_user_external_principal**](docs/ExternalApi.md#create_user_external_principal) | **POST** /auth/users/{userId}/external/principals | attach external principal to user *ExternalApi* | [**delete_user_external_principal**](docs/ExternalApi.md#delete_user_external_principal) | **DELETE** /auth/users/{userId}/external/principals | delete external principal from user *ExternalApi* | [**get_external_principal**](docs/ExternalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id diff --git a/clients/python/docs/ExperimentalApi.md b/clients/python/docs/ExperimentalApi.md index 18cbddba8d1..48fda6435a7 100644 --- a/clients/python/docs/ExperimentalApi.md +++ b/clients/python/docs/ExperimentalApi.md @@ -12,7 +12,7 @@ Method | HTTP request | Description [**get_external_principal**](ExperimentalApi.md#get_external_principal) | **GET** /auth/external/principals | describe external principal by id [**hard_reset_branch**](ExperimentalApi.md#hard_reset_branch) | **PUT** /repositories/{repository}/branches/{branch}/hard_reset | hard reset branch [**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 -[**s_ts_login**](ExperimentalApi.md#s_ts_login) | **POST** /sts/login | perform a login with STS +[**sts_login**](ExperimentalApi.md#sts_login) | **POST** /sts/login | perform a login with STS # **abort_presign_multipart_upload** @@ -941,8 +941,8 @@ 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) -# **s_ts_login** -> AuthenticationToken s_ts_login(sts_auth_request) +# **sts_login** +> AuthenticationToken sts_login(sts_auth_request) perform a login with STS @@ -973,11 +973,11 @@ with lakefs_sdk.ApiClient(configuration) as api_client: try: # perform a login with STS - api_response = api_instance.s_ts_login(sts_auth_request) - print("The response of ExperimentalApi->s_ts_login:\n") + api_response = api_instance.sts_login(sts_auth_request) + print("The response of ExperimentalApi->sts_login:\n") pprint(api_response) except Exception as e: - print("Exception when calling ExperimentalApi->s_ts_login: %s\n" % e) + print("Exception when calling ExperimentalApi->sts_login: %s\n" % e) ``` diff --git a/clients/python/docs/StsAuthRequest.md b/clients/python/docs/StsAuthRequest.md index 4a5fa686e82..430a34cdc0c 100644 --- a/clients/python/docs/StsAuthRequest.md +++ b/clients/python/docs/StsAuthRequest.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **code** | **str** | | **state** | **str** | | **redirect_uri** | **str** | | +**ttl_seconds** | **int** | The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. | [optional] ## Example diff --git a/clients/python/lakefs_sdk/api/experimental_api.py b/clients/python/lakefs_sdk/api/experimental_api.py index aa84c173901..aa75e9e789a 100644 --- a/clients/python/lakefs_sdk/api/experimental_api.py +++ b/clients/python/lakefs_sdk/api/experimental_api.py @@ -1347,13 +1347,13 @@ def list_user_external_principals_with_http_info(self, user_id : StrictStr, pref _request_auth=_params.get('_request_auth')) @validate_arguments - def s_ts_login(self, sts_auth_request : StsAuthRequest, **kwargs) -> AuthenticationToken: # noqa: E501 + def sts_login(self, sts_auth_request : StsAuthRequest, **kwargs) -> AuthenticationToken: # noqa: E501 """perform a login with STS # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.s_ts_login(sts_auth_request, async_req=True) + >>> thread = api.sts_login(sts_auth_request, async_req=True) >>> result = thread.get() :param sts_auth_request: (required) @@ -1371,17 +1371,17 @@ def s_ts_login(self, sts_auth_request : StsAuthRequest, **kwargs) -> Authenticat """ kwargs['_return_http_data_only'] = True if '_preload_content' in kwargs: - raise ValueError("Error! Please call the s_ts_login_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data") - return self.s_ts_login_with_http_info(sts_auth_request, **kwargs) # noqa: E501 + raise ValueError("Error! Please call the sts_login_with_http_info method with `_preload_content` instead and obtain raw data from ApiResponse.raw_data") + return self.sts_login_with_http_info(sts_auth_request, **kwargs) # noqa: E501 @validate_arguments - def s_ts_login_with_http_info(self, sts_auth_request : StsAuthRequest, **kwargs) -> ApiResponse: # noqa: E501 + def sts_login_with_http_info(self, sts_auth_request : StsAuthRequest, **kwargs) -> ApiResponse: # noqa: E501 """perform a login with STS # noqa: E501 This method makes a synchronous HTTP request by default. To make an asynchronous HTTP request, please pass async_req=True - >>> thread = api.s_ts_login_with_http_info(sts_auth_request, async_req=True) + >>> thread = api.sts_login_with_http_info(sts_auth_request, async_req=True) >>> result = thread.get() :param sts_auth_request: (required) @@ -1433,7 +1433,7 @@ def s_ts_login_with_http_info(self, sts_auth_request : StsAuthRequest, **kwargs) if _key not in _all_params: raise ApiTypeError( "Got an unexpected keyword argument '%s'" - " to method s_ts_login" % _key + " to method sts_login" % _key ) _params[_key] = _val del _params['kwargs'] diff --git a/clients/python/lakefs_sdk/models/sts_auth_request.py b/clients/python/lakefs_sdk/models/sts_auth_request.py index 935166480c1..c588f98d3f0 100644 --- a/clients/python/lakefs_sdk/models/sts_auth_request.py +++ b/clients/python/lakefs_sdk/models/sts_auth_request.py @@ -19,8 +19,8 @@ import json - -from pydantic import BaseModel, Field, StrictStr +from typing import Optional +from pydantic import BaseModel, Field, StrictInt, StrictStr class StsAuthRequest(BaseModel): """ @@ -29,7 +29,8 @@ class StsAuthRequest(BaseModel): code: StrictStr = Field(...) state: StrictStr = Field(...) redirect_uri: StrictStr = Field(...) - __properties = ["code", "state", "redirect_uri"] + ttl_seconds: Optional[StrictInt] = Field(None, description="The time-to-live for the generated token in seconds. The maximum value is 3600 seconds (1 hour) max is 12 hours. ") + __properties = ["code", "state", "redirect_uri", "ttl_seconds"] class Config: """Pydantic configuration""" @@ -69,7 +70,8 @@ def from_dict(cls, obj: dict) -> StsAuthRequest: _obj = StsAuthRequest.parse_obj({ "code": obj.get("code"), "state": obj.get("state"), - "redirect_uri": obj.get("redirect_uri") + "redirect_uri": obj.get("redirect_uri"), + "ttl_seconds": obj.get("ttl_seconds") }) return _obj diff --git a/clients/python/test/test_experimental_api.py b/clients/python/test/test_experimental_api.py index 97b1af0021e..f694e8cc23c 100644 --- a/clients/python/test/test_experimental_api.py +++ b/clients/python/test/test_experimental_api.py @@ -85,8 +85,8 @@ def test_list_user_external_principals(self): """ pass - def test_s_ts_login(self): - """Test case for s_ts_login + def test_sts_login(self): + """Test case for sts_login perform a login with STS # noqa: E501 """ diff --git a/clients/python/test/test_sts_auth_request.py b/clients/python/test/test_sts_auth_request.py index 0db3f1ccd81..3e2393357f7 100644 --- a/clients/python/test/test_sts_auth_request.py +++ b/clients/python/test/test_sts_auth_request.py @@ -41,7 +41,8 @@ def make_instance(self, include_optional): return StsAuthRequest( code = '', state = '', - redirect_uri = '' + redirect_uri = '', + ttl_seconds = 56 ) else : return StsAuthRequest( diff --git a/docs/assets/js/swagger.yml b/docs/assets/js/swagger.yml index 9f14917492c..bb163b02346 100644 --- a/docs/assets/js/swagger.yml +++ b/docs/assets/js/swagger.yml @@ -1062,6 +1062,12 @@ components: type: string redirect_uri: type: string + ttl_seconds: + type: integer + format: int64 + description: | + The time-to-live for the generated token in seconds. The default + value is 3600 seconds (1 hour) maximum time allowed is 12 hours. AuthenticationToken: type: object required: @@ -1818,7 +1824,7 @@ paths: post: tags: - experimental - operationId: STSLogin + operationId: stsLogin summary: perform a login with STS security: [] requestBody: diff --git a/pkg/api/auth_middleware_test.go b/pkg/api/auth_middleware_test.go index cd709367e59..684ef6809d1 100644 --- a/pkg/api/auth_middleware_test.go +++ b/pkg/api/auth_middleware_test.go @@ -171,7 +171,7 @@ func testGenerateBadAPIToken(t testing.TB, authService auth.Service) string { expires := now.Add(time.Hour) userID := "2906" // Generate a JWT for a nonexistent user. It will fail authentication. - tokenString, err := api.GenerateJWTLogin(secret, userID, now.Unix(), expires.Unix()) + tokenString, err := api.GenerateJWTLogin(secret, userID, now, expires) if err != nil { t.Fatal("Generate (bad) JWT token:", err) } diff --git a/pkg/api/controller.go b/pkg/api/controller.go index 31e67e2b416..8c9125c284a 100644 --- a/pkg/api/controller.go +++ b/pkg/api/controller.go @@ -54,6 +54,9 @@ const ( // DefaultPerPage is the default number of results returned for paginated queries to the API DefaultPerPage int = 100 + defaultSTSTTLSeconds = 3600 + maxSTSTTLSeconds = 3600 * 12 + lakeFSPrefix = "symlinks" actionStatusCompleted = "completed" @@ -536,7 +539,7 @@ func (c *Controller) Login(w http.ResponseWriter, r *http.Request, body apigen.L expires := loginTime.Add(duration) secret := c.Auth.SecretStore().SharedSecret() - tokenString, err := GenerateJWTLogin(secret, user.Username, loginTime.Unix(), expires.Unix()) + tokenString, err := GenerateJWTLogin(secret, user.Username, loginTime, expires) if err != nil { writeError(w, r, http.StatusInternalServerError, http.StatusText(http.StatusInternalServerError)) return @@ -556,22 +559,32 @@ func (c *Controller) Login(w http.ResponseWriter, r *http.Request, body apigen.L writeResponse(w, r, http.StatusOK, response) } -func (c *Controller) STSLogin(w http.ResponseWriter, r *http.Request, body apigen.STSLoginJSONRequestBody) { +func (c *Controller) StsLogin(w http.ResponseWriter, r *http.Request, body apigen.StsLoginJSONRequestBody) { ctx := r.Context() - responseData, err := c.Authentication.ValidateSTS(ctx, body.Code, body.RedirectUri, body.State) + externalUserID, err := c.Authentication.ValidateSTS(ctx, body.Code, body.RedirectUri, body.State) if c.handleAPIError(ctx, w, r, err) { return } // validate a user exists with the external user id - _, err = c.Auth.GetUserByExternalID(ctx, responseData.ExternalUserID) + _, err = c.Auth.GetUserByExternalID(ctx, externalUserID) if c.handleAPIError(ctx, w, r, err) { return } - token, err := GenerateJWTLogin(c.Auth.SecretStore().SharedSecret(), responseData.ExternalUserID, time.Now().Unix(), responseData.ExpiresAtUnixTime) + expiresInSec := defaultSTSTTLSeconds + if body.TtlSeconds != nil { + expiresInSec = min(maxSTSTTLSeconds, int(*body.TtlSeconds)) + } + now := time.Now() + expiresAt := now.Add(time.Duration(expiresInSec) * time.Second) + token, err := GenerateJWTLogin(c.Auth.SecretStore().SharedSecret(), externalUserID, now, expiresAt) if c.handleAPIError(ctx, w, r, err) { return } - writeResponse(w, r, http.StatusOK, token) + responseToken := apigen.AuthenticationToken{ + Token: token, + TokenExpiration: swag.Int64(expiresAt.Unix()), + } + writeResponse(w, r, http.StatusOK, responseToken) } func (c *Controller) GetPhysicalAddress(w http.ResponseWriter, r *http.Request, repository, branch string, params apigen.GetPhysicalAddressParams) { @@ -2638,7 +2651,8 @@ func (c *Controller) handleAPIErrorCallback(ctx context.Context, w http.Response cb(w, r, http.StatusPreconditionFailed, "Precondition failed") case errors.Is(err, authentication.ErrNotImplemented): cb(w, r, http.StatusNotImplemented, "Not implemented") - case errors.Is(err, authentication.ErrInvalidSTS): + case errors.Is(err, authentication.ErrInsufficientPermissions): + c.Logger.WithContext(ctx).WithError(err).Info("User verification failed - insufficient permissions") cb(w, r, http.StatusUnauthorized, http.StatusText(http.StatusUnauthorized)) case err != nil: c.Logger.WithContext(ctx).WithError(err).Error("API call returned status internal server error") diff --git a/pkg/api/controller_test.go b/pkg/api/controller_test.go index 3e9e4945754..70c87ea8e55 100644 --- a/pkg/api/controller_test.go +++ b/pkg/api/controller_test.go @@ -3736,7 +3736,7 @@ func TestController_STSLogin(t *testing.T) { server := setupServer(t, handler) clt := setupClientByEndpoint(t, server.URL, "", "") - res, err := clt.STSLoginWithResponse(context.Background(), apigen.STSLoginJSONRequestBody{}) + res, err := clt.StsLoginWithResponse(context.Background(), apigen.StsLoginJSONRequestBody{}) if err != nil { t.Fatalf("Error login with response %v", err) } diff --git a/pkg/api/jwt_login.go b/pkg/api/jwt_login.go index a3b0c4532f5..e5e1d10ee62 100644 --- a/pkg/api/jwt_login.go +++ b/pkg/api/jwt_login.go @@ -1,6 +1,8 @@ package api import ( + "time" + "github.com/golang-jwt/jwt" "github.com/google/uuid" ) @@ -12,13 +14,13 @@ const ( // GenerateJWTLogin creates a jwt token which can be used for authentication during login only, i.e. it will not work for password reset. // It supports backward compatibility for creating a login jwt. The audience is not set for login token. Any audience will make the token // invalid for login. No email is passed to support the ability of login for users via user/access keys which don't have an email yet -func GenerateJWTLogin(secret []byte, userID string, issuedAtUnixTime, expiresAtUnixTime int64) (string, error) { +func GenerateJWTLogin(secret []byte, userID string, issuedAt, expiresAt time.Time) (string, error) { claims := &jwt.StandardClaims{ Id: uuid.NewString(), Audience: LoginAudience, Subject: userID, - IssuedAt: issuedAtUnixTime, - ExpiresAt: expiresAtUnixTime, + IssuedAt: issuedAt.Unix(), + ExpiresAt: expiresAt.Unix(), } token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) return token.SignedString(secret) diff --git a/pkg/authentication/errors.go b/pkg/authentication/errors.go index d26a4a10648..54cce837b86 100644 --- a/pkg/authentication/errors.go +++ b/pkg/authentication/errors.go @@ -5,7 +5,6 @@ import ( ) var ( - ErrInvalidSTS = errors.New("invalid sts") ErrNotImplemented = errors.New("not implemented") ErrAlreadyExists = errors.New("already exists") ErrInsufficientPermissions = errors.New("insufficient permissions") diff --git a/pkg/authentication/service.go b/pkg/authentication/service.go index 2e26165139f..a9efdc8cd00 100644 --- a/pkg/authentication/service.go +++ b/pkg/authentication/service.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "net/http" - "strconv" "github.com/getkin/kin-openapi/openapi3filter" "github.com/treeverse/lakefs/pkg/authentication/apiclient" @@ -15,7 +14,8 @@ import ( ) type Service interface { - ValidateSTS(ctx context.Context, code, redirectURI, state string) (*STSResponseData, error) + // ValidateSTS validates the STS parameters and returns the external user ID + ValidateSTS(ctx context.Context, code, redirectURI, state string) (string, error) } type DummyService struct{} @@ -23,8 +23,8 @@ type DummyService struct{} func NewDummyService() *DummyService { return &DummyService{} } -func (d DummyService) ValidateSTS(ctx context.Context, code, redirectURI, state string) (*STSResponseData, error) { - return nil, ErrNotImplemented +func (d DummyService) ValidateSTS(ctx context.Context, code, redirectURI, state string) (string, error) { + return "", ErrNotImplemented } type APIService struct { @@ -73,48 +73,32 @@ func (s *APIService) validateResponse(resp openapi3filter.StatusCoder, expectedS } } -type STSResponseData struct { - ExternalUserID string - ExpiresAtUnixTime int64 -} - // ValidateSTS calls the external authentication service to validate the STS parameters // validates the required claims and returns the external user id and expiration time -func (s *APIService) ValidateSTS(ctx context.Context, code, redirectURI, state string) (*STSResponseData, error) { +func (s *APIService) ValidateSTS(ctx context.Context, code, redirectURI, state string) (string, error) { res, err := s.apiClient.STSLoginWithResponse(ctx, apiclient.STSLoginJSONRequestBody{ Code: code, RedirectUri: redirectURI, State: state, }) if err != nil { - return nil, fmt.Errorf("failed to authenticate user: %w", err) + return "", fmt.Errorf("failed to authenticate user: %w", err) } if err := s.validateResponse(res, http.StatusOK); err != nil { - return nil, fmt.Errorf("failed to authenticate user: %w", err) + return "", fmt.Errorf("invalid authentication response: %w", err) } // validate claims claims := res.JSON200.Claims for claim, expectedValue := range s.validateIDTokenClaims { if claimValue, found := claims.Get(claim); !found || claimValue != expectedValue { - return nil, fmt.Errorf("claim %s has unexpected value %s: %w", claim, claimValue, ErrInvalidSTS) + return "", fmt.Errorf("claim %s has unexpected value %s: %w", claim, claimValue, ErrInsufficientPermissions) } } subject, found := claims.Get("sub") if !found { - return nil, fmt.Errorf("missing subject in claims: %w", ErrInvalidSTS) - } - expiresAt, found := claims.Get("exp") - if !found { - return nil, fmt.Errorf("missing expiration in claims: %w", ErrInvalidSTS) + return "", fmt.Errorf("missing subject in claims: %w", ErrInsufficientPermissions) } - expiresAtInt, err := strconv.ParseFloat(expiresAt, 64) - if err != nil { - return nil, fmt.Errorf("failed to parse expiration time: %w", err) - } - return &STSResponseData{ - ExternalUserID: subject, - ExpiresAtUnixTime: int64(expiresAtInt), - }, nil + return subject, nil } diff --git a/pkg/authentication/service_test.go b/pkg/authentication/service_test.go index 8b7f94741af..78bf8821094 100644 --- a/pkg/authentication/service_test.go +++ b/pkg/authentication/service_test.go @@ -3,10 +3,8 @@ package authentication_test import ( "context" "errors" - "fmt" "net/http" "testing" - "time" "github.com/golang/mock/gomock" "github.com/treeverse/lakefs/pkg/authentication" @@ -27,14 +25,12 @@ func TestAPIAuthService_STSLogin(t *testing.T) { validateClaim string validateClaimValue string returnedSubject string - returnedExpiresUnix int64 }{ { - name: "ok", - responseStatusCode: http.StatusOK, - expectedErr: nil, - returnedSubject: "external_user_id", - returnedExpiresUnix: 12345678, + name: "ok", + responseStatusCode: http.StatusOK, + expectedErr: nil, + returnedSubject: "external_user_id", }, { name: "With additional claim", @@ -45,12 +41,11 @@ func TestAPIAuthService_STSLogin(t *testing.T) { validateClaim: "additional_claim", validateClaimValue: "additional_claim_value", returnedSubject: "external_user_id", - returnedExpiresUnix: 12345678, }, { name: "Non matching additional claim", responseStatusCode: http.StatusOK, - expectedErr: authentication.ErrInvalidSTS, + expectedErr: authentication.ErrInsufficientPermissions, additionalClaim: "additional_claim", additionalClaimValue: "additional_claim_value", validateClaim: "additional_claim", @@ -58,16 +53,9 @@ func TestAPIAuthService_STSLogin(t *testing.T) { returnedSubject: "external_user_id", }, { - name: "Missing subject", - responseStatusCode: http.StatusOK, - expectedErr: authentication.ErrInvalidSTS, - returnedExpiresUnix: 12345678, - }, - { - name: "Missing expires", + name: "Missing subject", responseStatusCode: http.StatusOK, - expectedErr: authentication.ErrInvalidSTS, - returnedSubject: "external_user_id", + expectedErr: authentication.ErrInsufficientPermissions, }, { name: "Not authorized", @@ -115,28 +103,18 @@ func TestAPIAuthService_STSLogin(t *testing.T) { if tt.returnedSubject != "" { loginResponse.JSON200.Claims.AdditionalProperties["sub"] = tt.returnedSubject } - if tt.returnedExpiresUnix != 0 { - floatExpires := float64(tt.returnedExpiresUnix) - loginResponse.JSON200.Claims.AdditionalProperties["exp"] = fmt.Sprint(floatExpires) - } + } mockClient.EXPECT().STSLoginWithResponse(gomock.Any(), requestEq).Return(loginResponse, tt.error) - res, err := s.ValidateSTS(ctx, code, redirectURI, state) + externalUserID, err := s.ValidateSTS(ctx, code, redirectURI, state) if !errors.Is(err, tt.expectedErr) { t.Fatalf("ValidateSTS: expected err: %v got: %v", tt.expectedErr, err) } if err != nil { return } - if res == nil { - t.Fatal("expected token data, got nil") - } - if res.ExternalUserID != tt.returnedSubject { - t.Fatalf("expected subject to be 'external_user_id', got %s", res.ExternalUserID) - } - expires := time.Unix(tt.returnedExpiresUnix, 0) - if res.ExpiresAtUnixTime != expires.Unix() { - t.Fatalf("expected expires at to be %d, got %d", expires.Unix(), res.ExpiresAtUnixTime) + if externalUserID != tt.returnedSubject { + t.Fatalf("expected subject to be 'external_user_id', got %s", externalUserID) } }) }