diff --git a/CHANGELOG.md b/CHANGELOG.md index e739e1e4b..3785edbe3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed +## [1.1.1] - 2024-03-20 + +### Changed + +- Fixed a bug where not providing scopes to `AzureIdentityAccessTokenProvider` failed with `UnsupportedOperationException` when attempting to fetch the token. [microsoftgraph/msgraph-sdk-java#1882](https://github.com/microsoftgraph/msgraph-sdk-java/issues/1882) + ## [1.1.0] - 2024-02-14 ### Added diff --git a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java index 162d02747..b95911616 100644 --- a/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java +++ b/components/authentication/azure/src/main/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProvider.java @@ -63,7 +63,7 @@ public AzureIdentityAccessTokenProvider( if (scopes == null) { _scopes = new ArrayList(); } else { - _scopes = Arrays.asList(scopes); + _scopes = new ArrayList<>(Arrays.asList(scopes)); } if (allowedHosts == null || allowedHosts.length == 0) { _hostValidator = new AllowedHostsValidator(); @@ -128,13 +128,18 @@ public AzureIdentityAccessTokenProvider( "com.microsoft.kiota.authentication.additional_claims_provided", decodedClaim != null && !decodedClaim.isEmpty()); - final TokenRequestContext context = new TokenRequestContext(); - if (_scopes.isEmpty()) { - _scopes.add(uri.getScheme() + "://" + uri.getHost() + "/.default"); + List scopes; + if (!_scopes.isEmpty()) { + scopes = new ArrayList<>(_scopes); + } else { + scopes = new ArrayList<>(); + scopes.add(uri.getScheme() + "://" + uri.getHost() + "/.default"); } - context.setScopes(_scopes); + + final TokenRequestContext context = new TokenRequestContext(); + context.setScopes(scopes); span.setAttribute( - "com.microsoft.kiota.authentication.scopes", String.join("|", _scopes)); + "com.microsoft.kiota.authentication.scopes", String.join("|", scopes)); if (decodedClaim != null && !decodedClaim.isEmpty()) { context.setClaims(decodedClaim); } diff --git a/components/authentication/azure/src/test/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProviderTest.java b/components/authentication/azure/src/test/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProviderTest.java index 8b7ef127b..3dd49bb1f 100644 --- a/components/authentication/azure/src/test/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProviderTest.java +++ b/components/authentication/azure/src/test/java/com/microsoft/kiota/authentication/AzureIdentityAccessTokenProviderTest.java @@ -1,19 +1,27 @@ package com.microsoft.kiota.authentication; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertLinesMatch; +import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.*; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; import com.azure.core.credential.AccessToken; import com.azure.core.credential.TokenCredential; import com.azure.core.credential.TokenRequestContext; +import org.junit.jupiter.api.Test; import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.NullAndEmptySource; import org.junit.jupiter.params.provider.ValueSource; +import org.mockito.ArgumentCaptor; import java.net.URI; import java.net.URISyntaxException; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; public class AzureIdentityAccessTokenProviderTest { @@ -41,4 +49,57 @@ void testNonLocalhostHttpUrlIsInvalid(String urlString) { accessTokenProvider.getAuthorizationToken( new URI(urlString), new HashMap<>())); } + + @Test + void testKeepUserProvidedScopes() throws URISyntaxException { + var tokenCredential = mock(TokenCredential.class); + String[] userProvidedScopes = { + "https://graph.microsoft.com/User.Read", "https://graph.microsoft.com/Application.Read" + }; + var accessTokenProvider = + new AzureIdentityAccessTokenProvider( + tokenCredential, new String[] {}, userProvidedScopes); + assertScopes(tokenCredential, accessTokenProvider, userProvidedScopes); + } + + @Test + void testConfigureDefaultScopeWhenScopesNotProvided() throws URISyntaxException { + var tokenCredential = mock(TokenCredential.class); + var accessTokenProvider = + new AzureIdentityAccessTokenProvider(tokenCredential, new String[] {}); + assertScopes( + tokenCredential, + accessTokenProvider, + new String[] {"https://graph.microsoft.com/.default"}); + } + + @ParameterizedTest + @NullAndEmptySource + void testConfigureDefaultScopeWhenScopesNullOrEmpty(String[] nullOrEmptyUserProvidedScopes) + throws URISyntaxException { + var tokenCredential = mock(TokenCredential.class); + var accessTokenProvider = + new AzureIdentityAccessTokenProvider( + tokenCredential, new String[] {}, nullOrEmptyUserProvidedScopes); + assertScopes( + tokenCredential, + accessTokenProvider, + new String[] {"https://graph.microsoft.com/.default"}); + } + + private static void assertScopes( + TokenCredential tokenCredential, + AzureIdentityAccessTokenProvider accessTokenProvider, + String[] expectedScopes) + throws URISyntaxException { + var tokenRequestContextArgumentCaptor = ArgumentCaptor.forClass(TokenRequestContext.class); + when(tokenCredential.getTokenSync(tokenRequestContextArgumentCaptor.capture())) + .thenReturn(mock(AccessToken.class)); + + accessTokenProvider.getAuthorizationToken( + new URI("https://graph.microsoft.com"), new HashMap<>()); + + List actualScopes = tokenRequestContextArgumentCaptor.getValue().getScopes(); + assertLinesMatch(Arrays.asList(expectedScopes), actualScopes); + } } diff --git a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/options/UserAgentHandlerOption.java b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/options/UserAgentHandlerOption.java index 85f12d7d4..f39687827 100644 --- a/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/options/UserAgentHandlerOption.java +++ b/components/http/okHttp/src/main/java/com/microsoft/kiota/http/middleware/options/UserAgentHandlerOption.java @@ -13,7 +13,7 @@ public UserAgentHandlerOption() {} private boolean enabled = true; @Nonnull private String productName = "kiota-java"; - @Nonnull private String productVersion = "1.0.6"; + @Nonnull private String productVersion = "1.1.1"; /** * Gets the product name to be used in the user agent header diff --git a/gradle.properties b/gradle.properties index 5b73eeac9..ed1814fba 100644 --- a/gradle.properties +++ b/gradle.properties @@ -26,7 +26,7 @@ org.gradle.caching=true mavenGroupId = com.microsoft.kiota mavenMajorVersion = 1 mavenMinorVersion = 1 -mavenPatchVersion = 0 +mavenPatchVersion = 1 mavenArtifactSuffix = #These values are used to run functional tests