Skip to content

Commit

Permalink
Merge pull request #1577 from microsoft/feature/java-cae
Browse files Browse the repository at this point in the history
CAE support for java
  • Loading branch information
baywet authored May 20, 2022
2 parents 2162893 + 906d8f7 commit eb7bd85
Show file tree
Hide file tree
Showing 16 changed files with 209 additions and 44 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Added support for discriminator downcast in PHP. [#1255](https://github.com/microsoft/kiota/issues/1255)
- Added support for multiple collections indexing under the same parent.
- Added code exclusions placeholder in the generation. (oneOf)
- Added support for continuous access evaluation in Java. [#1179](https://github.com/microsoft/kiota/issues/1179)

### Changed

Expand Down
2 changes: 1 addition & 1 deletion abstractions/java/lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-abstractions'
version '1.0.35'
version '1.0.36'
from(components.java)
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package com.microsoft.kiota.authentication;

import java.net.URI;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/** Returns access tokens */
public interface AccessTokenProvider {
/**
* This method returns the access token for the provided url.
* @param uri The target URI to get an access token for.
* @param additionalAuthenticationContext Additional authentication context to pass to the authentication library.
* @return A CompletableFuture that holds the access token.
*/
@Nonnull
CompletableFuture<String> getAuthorizationToken(@Nonnull final URI uri);
CompletableFuture<String> getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map<String, Object> additionalAuthenticationContext);
/**
* Returns the allowed hosts validator.
* @return The allowed hosts validator.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,12 @@

import com.microsoft.kiota.RequestInformation;

import java.util.Map;
import java.util.concurrent.CompletableFuture;

/** This authentication provider does not perform any authentication. */
public class AnonymousAuthenticationProvider implements AuthenticationProvider {
public CompletableFuture<Void> authenticateRequest(final RequestInformation request) {
public CompletableFuture<Void> authenticateRequest(final RequestInformation request, final Map<String, Object> additionalAuthenticationContext) {
return CompletableFuture.completedFuture(null);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,20 @@

import com.microsoft.kiota.RequestInformation;

import java.util.Map;
import java.util.concurrent.CompletableFuture;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

/** Authenticates the application request. */
public interface AuthenticationProvider {
/**
* Authenticates the application request.
* @param request the request to authenticate.
* @param additionalAuthenticationContext Additional authentication context to pass to the authentication library.
* @return a CompletableFuture to await for the authentication to be completed.
*/
@Nonnull
CompletableFuture<Void> authenticateRequest(@Nonnull final RequestInformation request);
CompletableFuture<Void> authenticateRequest(@Nonnull final RequestInformation request, @Nullable final Map<String, Object> additionalAuthenticationContext);
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import java.net.URI;
import java.net.URISyntaxException;
import java.util.concurrent.CompletableFuture;
import java.util.Map;
import java.util.Objects;

import javax.annotation.Nonnull;
Expand All @@ -16,16 +17,24 @@ public BaseBearerTokenAuthenticationProvider(@Nonnull final AccessTokenProvider
}
private final AccessTokenProvider accessTokenProvider;
private final static String authorizationHeaderKey = "Authorization";
public CompletableFuture<Void> authenticateRequest(final RequestInformation request) {
private final static String ClaimsKey = "claims";
public CompletableFuture<Void> authenticateRequest(final RequestInformation request, final Map<String, Object> additionalAuthenticationContext) {
Objects.requireNonNull(request);

if (request.getRequestHeaders().keySet().contains(authorizationHeaderKey) &&
additionalAuthenticationContext != null &&
additionalAuthenticationContext.containsKey(ClaimsKey))
{
request.removeRequestHeader(authorizationHeaderKey);
}
if(!request.getRequestHeaders().keySet().contains(authorizationHeaderKey)) {
final URI targetUri;
try {
targetUri = request.getUri();
} catch (URISyntaxException e) {
return CompletableFuture.failedFuture(e);
}
return this.accessTokenProvider.getAuthorizationToken(targetUri)
return this.accessTokenProvider.getAuthorizationToken(targetUri, additionalAuthenticationContext)
.thenApply(token -> {
if(token != null && !token.isEmpty()) {
// Not an error, just no need to authenticate as we might have been given an external URL from the main API (large file upload, etc.)
Expand Down
6 changes: 4 additions & 2 deletions authentication/java/azure/lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -29,14 +29,16 @@ repositories {
dependencies {
// Use JUnit Jupiter API for testing.
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.2'
testImplementation 'org.mockito:mockito-inline:4.5.1'


// Use JUnit Jupiter Engine for testing.
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'

// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:31.1-jre'
api 'com.azure:azure-core:1.28.0'
api 'com.microsoft.kiota:kiota-abstractions:1.0.25'
api 'com.microsoft.kiota:kiota-abstractions:1.0.36'
}

publishing {
Expand All @@ -53,7 +55,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-authentication-azure'
version '1.0.6'
version '1.0.7'
from(components.java)
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@

import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Base64;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.azure.core.credential.TokenCredential;
import com.azure.core.credential.TokenRequestContext;
Expand Down Expand Up @@ -41,17 +44,30 @@ public AzureIdentityAccessTokenProvider(@Nonnull final TokenCredential tokenCred
_hostValidator = new AllowedHostsValidator(allowedHosts);
}
}
private final static String ClaimsKey = "claims";
@Nonnull
public CompletableFuture<String> getAuthorizationToken(@Nonnull final URI uri) {
public CompletableFuture<String> getAuthorizationToken(@Nonnull final URI uri, @Nullable final Map<String, Object> additionalAuthenticationContext) {
if(!_hostValidator.isUrlHostValid(uri)) {
return CompletableFuture.completedFuture("");
}
if(!uri.getScheme().equalsIgnoreCase("https")) {
return CompletableFuture.failedFuture(new IllegalArgumentException("Only https is supported"));
}
return this.creds.getToken(new TokenRequestContext() {{

String decodedClaim = null;

if(additionalAuthenticationContext != null && additionalAuthenticationContext.containsKey(ClaimsKey) && additionalAuthenticationContext.get(ClaimsKey) instanceof String) {
final String rawClaim = (String) additionalAuthenticationContext.get(ClaimsKey);
decodedClaim = new String(Base64.getDecoder().decode(rawClaim));
}

final TokenRequestContext context = new TokenRequestContext() {{
this.setScopes(_scopes);
}}).toFuture().thenApply(r -> r.getToken());
}};
if(decodedClaim != null && !decodedClaim.isEmpty()) {
context.setClaims(decodedClaim);
}
return this.creds.getToken(context).toFuture().thenApply(r -> r.getToken());
}
@Nonnull
public AllowedHostsValidator getAllowedHostsValidator() {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* This Java source file was generated by the Gradle 'init' task.
*/
package com.microsoft.kiota.authentication;

import org.junit.jupiter.api.Test;

import reactor.core.publisher.Mono;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.HashMap;

import com.azure.core.credential.AccessToken;
import com.azure.core.credential.TokenCredential;
import com.azure.core.credential.TokenRequestContext;
import com.microsoft.kiota.HttpMethod;
import com.microsoft.kiota.RequestInformation;

class AzureIdentityAccessTokenProviderTest {
@Test
void testAddsClaimsToTheTokenContext() throws URISyntaxException {
final var credentialMock = mock(TokenCredential.class);
when(credentialMock.getToken(any(TokenRequestContext.class))).thenAnswer(r -> {
final var context = (TokenRequestContext) r.getArgument(0);
assertEquals(context.getClaims(), "{\"access_token\":{\"nbf\":{\"essential\":true, \"value\":\"1652813508\"}}}");
return Mono.just(mock(AccessToken.class));
});
final var authenticationProvider = new AzureIdentityAuthenticationProvider(credentialMock, null, "User.Read");
final var testRequest = new RequestInformation() {{
this.httpMethod = HttpMethod.GET;
this.setUri(new URI("https://graph.microsoft.com/v1.0/me"));
}};
final var additionalContext = new HashMap<String, Object>() {{
this.put("claims", "eyJhY2Nlc3NfdG9rZW4iOnsibmJmIjp7ImVzc2VudGlhbCI6dHJ1ZSwgInZhbHVlIjoiMTY1MjgxMzUwOCJ9fX0=");
}};
authenticationProvider.authenticateRequest(testRequest, additionalContext);

verify(credentialMock, times(1)).getToken(any(TokenRequestContext.class));
}
}

This file was deleted.

4 changes: 2 additions & 2 deletions http/java/okhttp/lib/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ dependencies {
// This dependency is used internally, and not exposed to consumers on their own compile classpath.
implementation 'com.google.guava:guava:31.1-jre'
api 'com.squareup.okhttp3:okhttp:4.9.3'
api 'com.microsoft.kiota:kiota-abstractions:1.0.34'
api 'com.microsoft.kiota:kiota-abstractions:1.0.36'
}

publishing {
Expand All @@ -56,7 +56,7 @@ publishing {
publications {
gpr(MavenPublication) {
artifactId 'kiota-http-okhttplibrary'
version '1.0.20'
version '1.0.21'
from(components.java)
}
}
Expand Down
Loading

0 comments on commit eb7bd85

Please sign in to comment.