-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: User managed identity support added. (#24)
- Loading branch information
1 parent
038ba74
commit 4757709
Showing
5 changed files
with
271 additions
and
5 deletions.
There are no files selected for viewing
66 changes: 66 additions & 0 deletions
66
...wclient/mil/azureservices/identity/client/usermanaged/AzureUserManagedIdentityClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
/* | ||
* AzureSystemManagedIdentityClient.java | ||
* | ||
* 7 ago 2024 | ||
*/ | ||
package it.pagopa.swclient.mil.azureservices.identity.client.usermanaged; | ||
|
||
import java.net.URI; | ||
import java.util.Optional; | ||
|
||
import org.eclipse.microprofile.config.inject.ConfigProperty; | ||
|
||
import io.quarkus.logging.Log; | ||
import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; | ||
import io.smallrye.mutiny.Uni; | ||
import it.pagopa.swclient.mil.azureservices.identity.bean.AccessToken; | ||
import it.pagopa.swclient.mil.azureservices.identity.client.AzureIdentityClient; | ||
import jakarta.enterprise.context.ApplicationScoped; | ||
|
||
/** | ||
* <p> | ||
* Reactive client (it's a proxy of REST client) to get access token from Microsoft Entra ID by | ||
* means of User Managed Identity. | ||
* </p> | ||
* <p> | ||
* To use this method, the environment variable {@code IDENTITY_CLIENT_ID} must be set. | ||
* </p> | ||
* | ||
* @author Antonio Tarricone | ||
*/ | ||
@ApplicationScoped | ||
public class AzureUserManagedIdentityClient implements AzureIdentityClient { | ||
/** | ||
* <p> | ||
* Reactive REST client to get access token from Microsoft Entra ID by means of User Managed | ||
* Identity. | ||
* </p> | ||
* | ||
* @see it.pagopa.swclient.mil.azureservices.identity.client.usermanaged.AzureUserManagedIdentityRestClient | ||
* AzureSystemManagedIdentityRestClient | ||
*/ | ||
private AzureUserManagedIdentityRestClient restClient; | ||
|
||
/** | ||
* <p> | ||
* Constructor. | ||
* </p> | ||
* | ||
* @param identityEndpoint Endpoint to get access token by means of user managed identity | ||
*/ | ||
AzureUserManagedIdentityClient(@ConfigProperty(name = "IDENTITY_ENDPOINT") Optional<String> identityEndpoint) { | ||
Log.trace("Azure User Managed Identity client initialization"); | ||
restClient = QuarkusRestClientBuilder.newBuilder() | ||
.baseUri(URI.create(identityEndpoint.orElseThrow())) | ||
.build(AzureUserManagedIdentityRestClient.class); | ||
} | ||
|
||
/** | ||
* @see it.pagopa.swclient.mil.azureservices.identity.client.systemmanaged.AzureSystemManagedIdentityRestClient#getAccessToken(String) | ||
*/ | ||
@Override | ||
public Uni<AccessToken> getAccessToken(String scope) { | ||
Log.tracef("Get access token with System Managed Identity for %s", scope); | ||
return restClient.getAccessToken(scope); | ||
} | ||
} |
44 changes: 44 additions & 0 deletions
44
...ent/mil/azureservices/identity/client/usermanaged/AzureUserManagedIdentityRestClient.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,44 @@ | ||
/* | ||
* AzureUserManagedIdentityRestClient.java | ||
* | ||
* 17 ott 2024 | ||
*/ | ||
package it.pagopa.swclient.mil.azureservices.identity.client.usermanaged; | ||
|
||
import org.eclipse.microprofile.rest.client.annotation.ClientHeaderParam; | ||
|
||
import io.quarkus.rest.client.reactive.ClientQueryParam; | ||
import io.smallrye.mutiny.Uni; | ||
import it.pagopa.swclient.mil.azureservices.identity.bean.AccessToken; | ||
import jakarta.ws.rs.GET; | ||
import jakarta.ws.rs.Produces; | ||
import jakarta.ws.rs.QueryParam; | ||
import jakarta.ws.rs.core.MediaType; | ||
|
||
/** | ||
* <p> | ||
* Reactive REST client to get access token from Microsoft Entra ID by means of User Managed | ||
* Identity. | ||
* </p> | ||
* <p> | ||
* To use this method, the environment variable {@code IDENTITY_CLIENT_ID} must be set. | ||
* </p> | ||
* | ||
* @author Antonio Tarricone | ||
*/ | ||
public interface AzureUserManagedIdentityRestClient { | ||
/** | ||
* <p> | ||
* Retrieves an access token for an Azure resource. | ||
* </p> | ||
* | ||
* @param scope {@link it.pagopa.swclient.mil.azureservices.identity.bean.Scope Scope} | ||
* @return {@link it.pagopa.swclient.mil.azureservices.identity.bean.AccessToken AccessToken} | ||
*/ | ||
@GET | ||
@Produces(MediaType.APPLICATION_JSON) | ||
@ClientQueryParam(name = "api-version", value = "2019-08-01") | ||
@ClientQueryParam(name = "client_id", value = "${IDENTITY_CLIENT_ID}") | ||
@ClientHeaderParam(name = "x-identity-header", value = "${IDENTITY_HEADER}") | ||
Uni<AccessToken> getAccessToken(@QueryParam("resource") String scope); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
95 changes: 95 additions & 0 deletions
95
...ent/mil/azureservices/identity/client/usermanaged/AzureUserManagedIdentityClientTest.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
/* | ||
* AzureUserManagedIdentityClientTest.java | ||
* | ||
* 17 ott 2024 | ||
*/ | ||
package it.pagopa.swclient.mil.azureservices.identity.client.usermanaged; | ||
|
||
import static org.mockito.ArgumentMatchers.any; | ||
import static org.mockito.Mockito.mock; | ||
import static org.mockito.Mockito.mockStatic; | ||
import static org.mockito.Mockito.when; | ||
|
||
import java.net.URI; | ||
import java.time.Instant; | ||
import java.time.temporal.ChronoUnit; | ||
import java.util.Optional; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
import org.junit.jupiter.api.TestInfo; | ||
import org.mockito.MockedStatic; | ||
|
||
import io.quarkus.rest.client.reactive.QuarkusRestClientBuilder; | ||
import io.quarkus.test.junit.QuarkusTest; | ||
import io.smallrye.mutiny.Uni; | ||
import io.smallrye.mutiny.helpers.test.UniAssertSubscriber; | ||
import it.pagopa.swclient.mil.azureservices.identity.bean.AccessToken; | ||
import it.pagopa.swclient.mil.azureservices.identity.bean.Scope; | ||
|
||
/** | ||
* | ||
* @author Antonio.tarricone | ||
*/ | ||
@QuarkusTest | ||
class AzureUserManagedIdentityClientTest { | ||
/** | ||
* | ||
* @param testInfo | ||
*/ | ||
@BeforeEach | ||
void init(TestInfo testInfo) { | ||
String frame = "*".repeat(testInfo.getDisplayName().length() + 11); | ||
System.out.println(frame); | ||
System.out.printf("* %s: START *%n", testInfo.getDisplayName()); | ||
System.out.println(frame); | ||
} | ||
|
||
/** | ||
* | ||
*/ | ||
@Test | ||
void given_requestToGetAccessToken_when_requestIsDone_then_returnAccessToken() { | ||
/* | ||
* Mocking of REST client. | ||
*/ | ||
Instant now = Instant.now(); | ||
AccessToken accessToken = new AccessToken() | ||
.setExpiresOn(now.plus(5, ChronoUnit.MINUTES).getEpochSecond()) | ||
.setValue("access_token_string"); | ||
|
||
AzureUserManagedIdentityRestClient restClient = mock(AzureUserManagedIdentityRestClient.class); | ||
when(restClient.getAccessToken(Scope.STORAGE)) | ||
.thenReturn(Uni.createFrom() | ||
.item(accessToken)); | ||
|
||
/* | ||
* Mocking of QuarkusRestClientBuilder. | ||
*/ | ||
QuarkusRestClientBuilder clientBuilder = mock(QuarkusRestClientBuilder.class); | ||
|
||
when(clientBuilder.build(AzureUserManagedIdentityRestClient.class)) | ||
.thenReturn(restClient); | ||
|
||
when(clientBuilder.baseUri(any(URI.class))) | ||
.thenReturn(clientBuilder); | ||
|
||
/* | ||
* Mocking of QuarkusRestClientBuilder factory. | ||
*/ | ||
try (MockedStatic<QuarkusRestClientBuilder> restClientBuilderFactory = mockStatic(QuarkusRestClientBuilder.class)) { | ||
restClientBuilderFactory.when(() -> QuarkusRestClientBuilder.newBuilder()) | ||
.thenReturn(clientBuilder); | ||
|
||
/* | ||
* Test. | ||
*/ | ||
AzureUserManagedIdentityClient client = new AzureUserManagedIdentityClient(Optional.of("https://login.microsoftonline.com/")); | ||
client.getAccessToken(Scope.STORAGE) | ||
.subscribe() | ||
.withSubscriber(UniAssertSubscriber.create()) | ||
.awaitItem() | ||
.assertItem(accessToken); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters