Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 26 additions & 8 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
## Release (2025-MM-DD)
- `loadbalancer`: [v0.1.0](services/loadbalancer/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Load balancer service
- `alb`: [v0.1.0](services/alb/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Application load balancer service
- `objectstorage`: [v0.1.0](services/objectstorage/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Object storage service
- `serverupdate`: [v0.1.0](services/serverupdate/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Server Update service
- `core`: [v0.4.1](core/CHANGELOG.md/#v041)
- **Bugfix:** Add check in `KeyFlowAuthenticator` to prevent endless loops
- `iaas`: [v0.3.1](services/iaas/CHANGELOG.md#v031)
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1
- `resourcemanager`: [v0.4.1](services/resourcemanager/CHANGELOG.md#v041)
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1
- `loadbalancer`:
- [v0.1.1](services/loadbalancer/CHANGELOG.md#v011)
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1
- [v0.1.0](services/loadbalancer/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Load balancer service
- `alb`:
- [v0.1.1](services/alb/CHANGELOG.md#v011)
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1
- [v0.1.0](services/alb/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Application load balancer service
- `objectstorage`:
- [v0.1.1](services/objectstorage/CHANGELOG.md#v011)
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1
- [v0.1.0](services/objectstorage/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Object storage service
- `serverupdate`:
- [v0.1.1](services/serverupdate/CHANGELOG.md#v011)
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1
- [v0.1.0](services/serverupdate/CHANGELOG.md#v010)
- Initial onboarding of STACKIT Java SDK for Server Update service

## Release (2025-10-29)
- `core`:
Expand Down
3 changes: 3 additions & 0 deletions core/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v0.4.1
- **Bugfix:** Add check in `KeyFlowAuthenticator` to prevent endless loops

## v0.4.0
- **Feature:** Added core wait handler structure which can be used by every service waiter implementation.

Expand Down
2 changes: 1 addition & 1 deletion core/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.0
0.4.1
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ public class KeyFlowAuthenticator implements Authenticator {
/**
* Creates the initial service account and refreshes expired access token.
*
* <p>NOTE: It's normal that 2 requests are sent, it's regular OkHttp Authenticator behavior.
* The first request is always attempted without the authenticator and in case the response is
* Unauthorized(=401), OkHttp reattempt the request with the authenticator. See <a
* href="https://square.github.io/okhttp/recipes/#handling-authentication-kt-java">OkHttp
* Docs</a>
*
* @deprecated use constructor with OkHttpClient instead to prevent resource leaks. Will be
* removed in April 2026.
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
Expand All @@ -65,6 +71,12 @@ public KeyFlowAuthenticator(CoreConfiguration cfg, ServiceAccountKey saKey) {
/**
* Creates the initial service account and refreshes expired access token.
*
* <p>NOTE: It's normal that 2 requests are sent, it's regular OkHttp Authenticator behavior.
* The first request is always attempted without the authenticator and in case the response is
* Unauthorized(=401), OkHttp reattempt the request with the authenticator. See <a
* href="https://square.github.io/okhttp/recipes/#handling-authentication-kt-java">OkHttp
* Docs</a>
*
* @deprecated use constructor with OkHttpClient instead to prevent resource leaks. Will be
* removed in April 2026.
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
Expand All @@ -81,6 +93,12 @@ public KeyFlowAuthenticator(
/**
* Creates the initial service account and refreshes expired access token.
*
* <p>NOTE: It's normal that 2 requests are sent, it's regular OkHttp Authenticator behavior.
* The first request is always attempted without the authenticator and in case the response is
* Unauthorized(=401), OkHttp reattempt the request with the authenticator. See <a
* href="https://square.github.io/okhttp/recipes/#handling-authentication-kt-java">OkHttp
* Docs</a>
*
* @param httpClient OkHttpClient object
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
*/
Expand All @@ -91,6 +109,12 @@ public KeyFlowAuthenticator(OkHttpClient httpClient, CoreConfiguration cfg) thro
/**
* Creates the initial service account and refreshes expired access token.
*
* <p>NOTE: It's normal that 2 requests are sent, it's regular OkHttp Authenticator behavior.
* The first request is always attempted without the authenticator and in case the response is
* Unauthorized(=401), OkHttp reattempt the request with the authenticator. See <a
* href="https://square.github.io/okhttp/recipes/#handling-authentication-kt-java">OkHttp
* Docs</a>
*
* @param httpClient OkHttpClient object
* @param cfg Configuration to set a custom token endpoint and the token expiration leeway.
* @param saKey Service Account Key, which should be used for the authentication
Expand Down Expand Up @@ -129,6 +153,9 @@ protected KeyFlowAuthenticator(

@Override
public Request authenticate(Route route, @NotNull Response response) throws IOException {
if (response.request().header("Authorization") != null) {
return null; // Give up, we've already attempted to authenticate.
}
String accessToken;
try {
accessToken = getAccessToken();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,7 @@
import java.security.spec.InvalidKeySpecException;
import java.time.temporal.ChronoUnit;
import java.util.Date;
import okhttp3.HttpUrl;
import okhttp3.OkHttpClient;
import okhttp3.*;
import okhttp3.mockwebserver.MockResponse;
import okhttp3.mockwebserver.MockWebServer;
import org.junit.jupiter.api.AfterEach;
Expand Down Expand Up @@ -62,6 +61,9 @@ class KeyFlowAuthenticatorTest {
+ "h/9afEtu5aUE/m+1vGBoH8z1\n"
+ "-----END PRIVATE KEY-----\n";

private static final Request mockRequest =
new Request.Builder().url("https://stackit.com").get().build();

private ServiceAccountKey createDummyServiceAccount() {
ServiceAccountCredentials credentials =
new ServiceAccountCredentials("aud", "iss", "kid", PRIVATE_KEY, "sub");
Expand Down Expand Up @@ -270,4 +272,92 @@ void createAccessTokenWithRefreshTokenResponse200WithEmptyBodyThrowsException()
assertThrows(
JsonSyntaxException.class, keyFlowAuthenticator::createAccessTokenWithRefreshToken);
}

@Test
@DisplayName("authenticator sets Authorization header")
void authenticatorSetsAuthorizationHeaderIfNotAuthenticated()
throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
// Setup mockServer
final String authorizationHeader = "Authorization";
KeyFlowAuthenticator.KeyFlowTokenResponse mockResponse = mockResponseBody(false);
// mock response for KeyFlow authentication with mocked access token
MockResponse mockedResponse =
new MockResponse()
.setResponseCode(200)
.setBody(new Gson().toJson(mockResponse))
.addHeader("Content-type", "application/json");
mockWebServer.enqueue(mockedResponse);
HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH);

// Set unauthorized request
Response unauthorizedRequest =
new Response.Builder()
.request(mockRequest)
.code(401)
.message("Unauthorized")
.protocol(Protocol.HTTP_2)
.build();

// Config
CoreConfiguration cfg =
new CoreConfiguration().tokenCustomUrl(url.toString()); // Use mockWebServer

// Check if "Authorization" header is unset
assertNull(unauthorizedRequest.request().header(authorizationHeader));

// Prepare keyFlowAuthenticator
KeyFlowAuthenticator keyFlowAuthenticator =
new KeyFlowAuthenticator(httpClient, cfg, createDummyServiceAccount());
// authenticator creates new access token and sets it the Authorization header
Request newRequest = keyFlowAuthenticator.authenticate(null, unauthorizedRequest);

// Check if new request is not null
assertNotNull(newRequest);
// Check if the "Authorization" Header is set
assertNotNull(newRequest.header(authorizationHeader));
}

@Test
@DisplayName("Authenticator returns null when already authenticated")
void authenticatorReturnsNullWhenAlreadyAuthenticated()
throws NoSuchAlgorithmException, InvalidKeySpecException, IOException {
// Setup mockServer
final String authorizationHeader = "Authorization";
KeyFlowAuthenticator.KeyFlowTokenResponse mockResponse = mockResponseBody(false);
// mock response for KeyFlow authentication with mocked access token
MockResponse mockedResponse =
new MockResponse()
.setResponseCode(200)
.setBody(new Gson().toJson(mockResponse))
.addHeader("Content-type", "application/json");
mockWebServer.enqueue(mockedResponse);
HttpUrl url = mockWebServer.url(MOCK_WEBSERVER_PATH);

// Set unauthorized request
Response unauthorizedRequest =
new Response.Builder()
.request(
mockRequest
.newBuilder()
.addHeader(authorizationHeader, "<my-access-token>")
.build())
.code(401)
.message("Unauthorized")
.protocol(Protocol.HTTP_2)
.build(); // Unauthorized request

// Config
CoreConfiguration cfg =
new CoreConfiguration().tokenCustomUrl(url.toString()); // Use mockWebServer

// Check if "Authorization" header is set
assertNotNull(unauthorizedRequest.request().header(authorizationHeader));

// Prepare keyFlowAuthenticator
KeyFlowAuthenticator keyFlowAuthenticator =
new KeyFlowAuthenticator(httpClient, cfg, createDummyServiceAccount());

// Authenticator returns no new request, because "Authorization" header was already set
assertNull(keyFlowAuthenticator.authenticate(null, unauthorizedRequest));
}
}
3 changes: 3 additions & 0 deletions services/alb/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
## v0.1.1
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1

## v0.1.0
- Initial onboarding of STACKIT Java SDK for Application load balancer service
2 changes: 1 addition & 1 deletion services/alb/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.1.1
3 changes: 3 additions & 0 deletions services/iaas/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v0.3.1
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1

## v0.3.0
- **Feature:** Add `createdAt` and `updatedAt` attributes to `SecurityGroupRule`, `BaseSecurityGroupRule`, `CreateSecurityGroupRulePayload` model classes
- **Feature:** Add `description` attribute to `CreateNicPayload`, `NIC`, `UpdateNicPayload` model classes
Expand Down
2 changes: 1 addition & 1 deletion services/iaas/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.3.0
0.3.1
3 changes: 3 additions & 0 deletions services/loadbalancer/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
## v0.1.1
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1

## v0.1.0
- Initial onboarding of STACKIT Java SDK for Load balancer service
2 changes: 1 addition & 1 deletion services/loadbalancer/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.1.1
3 changes: 3 additions & 0 deletions services/objectstorage/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
## v0.1.1
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1

## v0.1.0
- Initial onboarding of STACKIT Java SDK for Object storage service
2 changes: 1 addition & 1 deletion services/objectstorage/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.1.1
3 changes: 3 additions & 0 deletions services/resourcemanager/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
## v0.4.1
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1

## v0.4.0
- **Feature:** Added waiter for project creation and project deletion

Expand Down
2 changes: 1 addition & 1 deletion services/resourcemanager/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.4.0
0.4.1
3 changes: 3 additions & 0 deletions services/serverupdate/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
## v0.1.1
- Bump dependency `cloud.stackit.sdk.core` to v0.4.1

## v0.1.0
- Initial onboarding of STACKIT Java SDK for Server Update service
2 changes: 1 addition & 1 deletion services/serverupdate/VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.1.0
0.1.1