Consolidate all Java RBAC sample work (#456)

* Adding Java RBAC sample
* Remove unwanted classpath and project files
* README with RBAC and MI instructions
This commit is contained in:
JamesBirdsall 2019-08-29 16:15:54 -07:00 коммит произвёл Serkant Karaca
Родитель 1a9a5401c4
Коммит c05dba7e76
5 изменённых файлов: 386 добавлений и 0 удалений

Просмотреть файл

@ -0,0 +1,42 @@
# Role based access sample with Azure Event Hubs Java SDK
For general information on using Role based access (RBAC) with Azure Event Hubs, see the [documentation](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-role-based-access-control).
This sample uses the [Microsoft Authentication Library (MSAL) for Java](https://github.com/AzureAD/microsoft-authentication-library-for-java) to obtain tokens from Azure Active Directory (AAD).
## Prerequisites
Please refer to the Java sample overview README for setting up the sample environment, including creating an Event Hubs cloud namespace and an event hub.
The specific AAD pattern used in this sample is ["Authenticate an appliction"](https://docs.microsoft.com/en-us/azure/event-hubs/authenticate-application). Please follow the steps described to
create an application (client) id and application (client) secret, obtain your directory (tenant) id, and assign the application the Data Owner role on your event hub.
Once you have performed the previous steps, edit SendReceive.java to provide the necessary information.
```java
final java.net.URI namespace = new java.net.URI("----EventHubsNamespace---.servicebus.windows.net"); // to target National clouds, change domain name too
final String eventhub = "----EventHubName----";
final String authority = "https://login.windows.net/----replaceWithTenantIdGuid----";
final String clientId = "----replaceWithClientIdGuid----"; // not needed to run with Managed Identity
final String clientSecret = "----replaceWithClientSecret----"; // not needed to run with Managed Identity
```
The Azure Event Hubs Java SDK also has limited built-in support for Managed Identity: specifically, when running in a virtual machine with a system-assigned managed identity, the SDK can
obtain and use that identity to perform role based access. This sample can demonstrate that ability when run in an
[appropriately-configured virtual machine](https://docs.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/qs-configure-portal-windows-vm) and the managed identity
[has been assigned the Data Owner role on your event hub.](https://docs.microsoft.com/en-us/azure/event-hubs/event-hubs-managed-service-identity)
## Build and run
The sample can be built independently with
```bash
mvn clean package
```
and then run with (or just from VS Code or another Java IDE)
```bash
java -jar ./target/send-1.0.0-jar-with-dependencies.jar
```

63
samples/Java/Rbac/pom.xml Normal file
Просмотреть файл

@ -0,0 +1,63 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>rbac</groupId>
<version>1.0.0</version>
<artifactId>rbac</artifactId>
<packaging>jar</packaging>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<debug>true</debug>
<debuglevel>lines,vars,source</debuglevel>
</configuration>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.microsoft.azure.eventhubs.samples.rbac.SendReceive</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-eventhubs</artifactId>
<version>3.0.0</version>
</dependency>
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.8.5</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>msal4j</artifactId>
<version>0.5.0-preview</version>
</dependency>
</dependencies>
</project>

Просмотреть файл

@ -0,0 +1,39 @@
/*
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
package com.microsoft.azure.eventhubs.samples.rbac;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import com.microsoft.aad.msal4j.*;
import com.microsoft.azure.eventhubs.AzureActiveDirectoryTokenProvider;
class AuthCallback implements AzureActiveDirectoryTokenProvider.AuthenticationCallback {
final private String clientId;
final private String clientSecret;
public AuthCallback(final String clientId, final String clientSecret) {
this.clientId = clientId;
this.clientSecret = clientSecret;
}
@Override
public CompletableFuture<String> acquireToken(String audience, String authority, Object state) {
try {
ConfidentialClientApplication app = ConfidentialClientApplication.builder(this.clientId, new ClientSecret(this.clientSecret))
.authority(authority)
.build();
ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton(audience + ".default")).build();
return app.acquireToken(parameters).thenApply((authResult) -> {
return authResult.accessToken();
});
} catch (Exception e) {
CompletableFuture<String> failed = new CompletableFuture<String>();
failed.completeExceptionally(e);
return failed;
}
}
}

Просмотреть файл

@ -0,0 +1,53 @@
/*
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
package com.microsoft.azure.eventhubs.samples.rbac;
import java.text.ParseException;
import java.time.Duration;
import java.util.Collections;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
import com.microsoft.aad.msal4j.*;
import com.microsoft.azure.eventhubs.*;
import com.microsoft.azure.eventhubs.impl.ClientConstants;
class CustomTokenProvider implements ITokenProvider {
final private String authority;
final private String audience = ClientConstants.EVENTHUBS_AUDIENCE;
final private String clientId;
final private String clientSecret;
public CustomTokenProvider(final String authority, final String clientId, final String clientSecret) {
this.authority = authority;
this.clientId = clientId;
this.clientSecret = clientSecret;
}
@Override
public CompletableFuture<SecurityToken> getToken(String resource, Duration timeout) {
try {
ConfidentialClientApplication app = ConfidentialClientApplication.builder(this.clientId, new ClientSecret(this.clientSecret))
.authority(authority)
.build();
ClientCredentialParameters parameters = ClientCredentialParameters.builder(Collections.singleton(audience + ".default")).build();
return app.acquireToken(parameters)
.thenApply((authResult) -> {
try {
return new JsonSecurityToken(authResult.accessToken(), resource);
} catch (ParseException e) {
throw new CompletionException(e);
}
});
}
catch (Exception e) {
CompletableFuture<SecurityToken> failed = new CompletableFuture<SecurityToken>();
failed.completeExceptionally(e);
return failed;
}
}
}

Просмотреть файл

@ -0,0 +1,189 @@
/*
* Copyright (c) Microsoft. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for full license information.
*/
package com.microsoft.azure.eventhubs.samples.rbac;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.microsoft.azure.eventhubs.AzureActiveDirectoryTokenProvider;
import com.microsoft.azure.eventhubs.ConnectionStringBuilder;
import com.microsoft.azure.eventhubs.EventData;
import com.microsoft.azure.eventhubs.EventHubClient;
import com.microsoft.azure.eventhubs.EventHubException;
import com.microsoft.azure.eventhubs.EventPosition;
import com.microsoft.azure.eventhubs.PartitionReceiver;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.Charset;
import java.time.Instant;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
public class SendReceive {
final java.net.URI namespace = new java.net.URI("----EventHubsNamespace---.servicebus.windows.net"); // to target National clouds, change domain name too
final String eventhub = "----EventHubName----";
final String authority = "https://login.windows.net/----replaceWithTenantIdGuid----";
final String clientId = "----replaceWithClientIdGuid----"; // not needed to run with Managed Identity
final String clientSecret = "----replaceWithClientSecret----"; // not needed to run with Managed Identity
public SendReceive() throws URISyntaxException {
}
public static int main(String[] args)
throws EventHubException, ExecutionException, InterruptedException, IOException, URISyntaxException {
SendReceive ss = new SendReceive();
return ss.run(args);
}
private int run(String[] args) throws IOException {
System.out.println("Choose an action:");
System.out.println("[A] Authenticate via Managed Identity");
System.out.println("[B] Get AAD token using AuthCallback");
System.out.println("[C] Get AAD token using AzureActiveDirectoryTokenProvider to wrap AuthCallback");
System.out.println("[D] Get AAD token using ITokenProvider implementation");
char key = (char)System.in.read();
char keyPressed = Character.toUpperCase(key);
try {
switch (keyPressed) {
case 'A':
managedIdentityScenario();
break;
case 'B':
useAuthCallback();
break;
case 'C':
useAADTokenProvider();
break;
case 'D':
useCustomTokenProvider();
break;
default:
System.out.println("Unknown command, press enter to exit");
System.in.read();
return -1;
}
}
catch (Exception ex) {
System.out.println("Error during execution. Exception: " + ex.toString());
return -1;
}
return 0;
}
private ScheduledExecutorService getScheduledExecutorService() {
// The Executor handles all asynchronous tasks and this is passed to the EventHubClient instance.
// This enables the user to segregate their thread pool based on the work load.
// This pool can then be shared across multiple EventHubClient instances.
// The following sample uses a single thread executor, as there is only one EventHubClient instance,
// handling different flavors of ingestion to Event Hubs here.
final ScheduledExecutorService executorService = Executors.newScheduledThreadPool(4);
return executorService;
}
private void managedIdentityScenario() throws IOException, EventHubException {
final ConnectionStringBuilder connStr = new ConnectionStringBuilder()
.setEndpoint(this.namespace)
.setEventHubName(this.eventhub)
.setAuthentication(ConnectionStringBuilder.MANAGED_IDENTITY_AUTHENTICATION);
ScheduledExecutorService executorService = getScheduledExecutorService();
final EventHubClient ehClient = EventHubClient.createFromConnectionStringSync(connStr.toString(), executorService);
sendReceive(ehClient, executorService);
}
private void useAuthCallback() throws IOException, InterruptedException, ExecutionException, EventHubException {
final AuthCallback callback = new AuthCallback(clientId, clientSecret);
ScheduledExecutorService executorService = getScheduledExecutorService();
final EventHubClient ehClient = EventHubClient.createWithAzureActiveDirectory(namespace, eventhub, callback, authority, executorService, null).get();
sendReceive(ehClient, executorService);
}
private void useAADTokenProvider() throws IOException, InterruptedException, ExecutionException, EventHubException {
final AuthCallback callback = new AuthCallback(clientId, clientSecret);
ScheduledExecutorService executorService = getScheduledExecutorService();
final AzureActiveDirectoryTokenProvider aadTokenProvider = new AzureActiveDirectoryTokenProvider(callback, authority, null);
final EventHubClient ehClient = EventHubClient.createWithTokenProvider(namespace, eventhub, aadTokenProvider, executorService, null).get();
sendReceive(ehClient, executorService);
}
private void useCustomTokenProvider() throws IOException, InterruptedException, ExecutionException, EventHubException {
final CustomTokenProvider tokenProvider = new CustomTokenProvider(authority, clientId, clientSecret);
ScheduledExecutorService executorService = getScheduledExecutorService();
final EventHubClient ehClient = EventHubClient.createWithTokenProvider(namespace, eventhub, tokenProvider, executorService, null).get();
sendReceive(ehClient, executorService);
}
private void sendReceive(EventHubClient ehClient, ScheduledExecutorService executorService) throws IOException, EventHubException {
try {
final Gson gson = new GsonBuilder().create();
for (int i = 0; i < 100; i++) {
String payload = "Message " + Integer.toString(i);
byte[] payloadBytes = gson.toJson(payload).getBytes(Charset.defaultCharset());
EventData sendEvent = EventData.create(payloadBytes);
ehClient.sendSync(sendEvent);
}
System.out.println(Instant.now() + ": Send Complete...");
final PartitionReceiver receiver = ehClient.createReceiverSync(
EventHubClient.DEFAULT_CONSUMER_GROUP_NAME,
"0",
EventPosition.fromStartOfStream());
Iterable<EventData> receivedEvents = receiver.receiveSync(100);
while (true) {
int batchSize = 0;
if (receivedEvents != null) {
for (final EventData receivedEvent : receivedEvents) {
if (receivedEvent.getBytes() != null)
System.out.println(String.format("Message Payload: %s", new String(receivedEvent.getBytes(), Charset.defaultCharset())));
System.out.println(String.format("Offset: %s, SeqNo: %s, EnqueueTime: %s",
receivedEvent.getSystemProperties().getOffset(),
receivedEvent.getSystemProperties().getSequenceNumber(),
receivedEvent.getSystemProperties().getEnqueuedTime()));
batchSize++;
}
}
else {
break;
}
System.out.println(String.format("ReceivedBatch Size: %s", batchSize));
receivedEvents = receiver.receiveSync(100);
}
System.out.println(Instant.now() + ": Receive Complete...");
System.out.println("Press Enter to stop.");
System.in.read();
} finally {
ehClient.closeSync();
executorService.shutdown();
}
}
}