Skip to content

Commit 15d04e3

Browse files
authored
add service linker sample (Azure#28333)
* add service linker sample * add special case in readme * add copyright and static userTokenPolicy class * update readme in sample folder * refine readme * add azure-service-linker in Test-SampleMetadata.ps1 * fix checkstyle * remove sample publish * fix typo * update readme
1 parent 849bdd8 commit 15d04e3

File tree

3 files changed

+272
-0
lines changed

3 files changed

+272
-0
lines changed

sdk/servicelinker/azure-resourcemanager-servicelinker/pom.xml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,17 @@
5151
<artifactId>azure-core-management</artifactId>
5252
<version>1.5.4</version> <!-- {x-version-update;com.azure:azure-core-management;dependency} -->
5353
</dependency>
54+
<dependency>
55+
<groupId>com.azure</groupId>
56+
<artifactId>azure-identity</artifactId>
57+
<version>1.5.0</version> <!-- {x-version-update;com.azure:azure-identity;dependency} -->
58+
<scope>test</scope>
59+
</dependency>
60+
<dependency>
61+
<groupId>com.azure.resourcemanager</groupId>
62+
<artifactId>azure-resourcemanager</artifactId>
63+
<version>2.14.0</version> <!-- {x-version-update;com.azure.resourcemanager:azure-resourcemanager;dependency} -->
64+
<scope>test</scope>
65+
</dependency>
5466
</dependencies>
5567
</project>
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
<!-- ---
2+
page_type: sample
3+
languages:
4+
- java
5+
products:
6+
- azure
7+
- azure-service-linker
8+
urlFragment: service-linker-resourcemanager-samples
9+
--- -->
10+
11+
# Azure Service Linker Create Connection Samples for Java
12+
13+
This contains Java samples for create service connection using Service Linker Provider.
14+
15+
## Getting started
16+
17+
Getting started explained in detail [here][SERVICELINKER_README_GETTING_STARTED].
18+
Please refer it to add dependency and configure authentication environment variables.
19+
20+
## Samples Details
21+
22+
All samples are located in [CreateServiceLinker][SERVICELINKER_SAMPLE_CODE] file, you can use `main()` entrypoint to run it directly.
23+
24+
### CreateSpringCloudAndSQLConnection
25+
26+
1. Create Spring Cloud App and Deployment
27+
2. Create SQL Database
28+
3. Setup connection between Spring Cloud App and SQL Database using username and password by creating Service Linker
29+
30+
### CreateWebAppAndKeyVaultConnectionWithUserIdentity
31+
32+
1. Create Web App
33+
2. Create Key Vault
34+
3. Create User Assigned Identity
35+
4. Setup connection between Web App and Key Vault using User Assigned Identity by creating Service Linker
36+
37+
### Special Case
38+
39+
The Service Linker provider need user token in a separated header in the following scenarios.
40+
41+
* The target resource is Key Vault
42+
* SecretStore is used to store secret in Key Vault
43+
* VNetSolutionInfo is specified
44+
45+
## Next steps
46+
47+
Start using Service Linker Java SDK in your solutions.
48+
49+
For more information about Service Linker, refer [here][SERVICELINKER_DOCS].
50+
51+
For more information about other Azure Management SDK, refer [here][MGMT_SDK_LINK].
52+
53+
<!-- LINKS -->
54+
[SERVICELINKER_README_GETTING_STARTED]: https://github.com/Azure/azure-sdk-for-java/tree/main/sdk/servicelinker/azure-resourcemanager-servicelinker#getting-started
55+
[SERVICELINKER_SAMPLE_CODE]: https://github.com/Azure/azure-sdk-for-java/blob/main/sdk/servicelinker/azure-resourcemanager-servicelinker/src/samples/java/com/azure/resourcemanager/servicelinker/CreateServiceLinker.java
56+
[SERVICELINKER_DOCS]: https://docs.microsoft.com/azure/service-connector
57+
[MGMT_SDK_LINK]: https://aka.ms/azsdk/java/mgmt
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,203 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
package com.azure.resourcemanager.servicelinker;
5+
6+
import com.azure.core.credential.AccessToken;
7+
import com.azure.core.credential.TokenCredential;
8+
import com.azure.core.credential.TokenRequestContext;
9+
import com.azure.core.http.HttpPipelineCallContext;
10+
import com.azure.core.http.HttpPipelineNextPolicy;
11+
import com.azure.core.http.HttpResponse;
12+
import com.azure.core.http.policy.HttpPipelinePolicy;
13+
import com.azure.core.management.AzureEnvironment;
14+
import com.azure.core.management.Region;
15+
import com.azure.core.management.profile.AzureProfile;
16+
import com.azure.identity.AzureAuthorityHosts;
17+
import com.azure.identity.DefaultAzureCredentialBuilder;
18+
import com.azure.resourcemanager.AzureResourceManager;
19+
import com.azure.resourcemanager.appplatform.models.SkuName;
20+
import com.azure.resourcemanager.appplatform.models.SpringApp;
21+
import com.azure.resourcemanager.appplatform.models.SpringService;
22+
import com.azure.resourcemanager.appservice.models.PricingTier;
23+
import com.azure.resourcemanager.appservice.models.RuntimeStack;
24+
import com.azure.resourcemanager.appservice.models.WebApp;
25+
import com.azure.resourcemanager.keyvault.models.Vault;
26+
import com.azure.resourcemanager.msi.models.Identity;
27+
import com.azure.resourcemanager.servicelinker.models.AzureResource;
28+
import com.azure.resourcemanager.servicelinker.models.ClientType;
29+
import com.azure.resourcemanager.servicelinker.models.LinkerResource;
30+
import com.azure.resourcemanager.servicelinker.models.SecretAuthInfo;
31+
import com.azure.resourcemanager.servicelinker.models.SourceConfiguration;
32+
import com.azure.resourcemanager.servicelinker.models.UserAssignedIdentityAuthInfo;
33+
import com.azure.resourcemanager.servicelinker.models.ValueSecretInfo;
34+
import com.azure.resourcemanager.sql.models.SqlDatabase;
35+
import com.azure.resourcemanager.sql.models.SqlServer;
36+
import reactor.core.publisher.Mono;
37+
38+
import java.util.Locale;
39+
import java.util.UUID;
40+
41+
public class CreateServiceLinker {
42+
private static final String USER_TOKEN_HEADER = "x-ms-serviceconnector-user-token";
43+
44+
/**
45+
* Main entry point.
46+
*
47+
* @param args the parameters
48+
*/
49+
public static void main(String[] args) throws Exception {
50+
// Authentication environment variables need to be set: AZURE_CLIENT_ID,AZURE_TENANT_ID,AZURE_CLIENT_SECRET,AZURE_SUBSCRIPTION_ID
51+
TokenCredential credential = new DefaultAzureCredentialBuilder()
52+
.authorityHost(AzureAuthorityHosts.AZURE_PUBLIC_CLOUD)
53+
.build();
54+
55+
AzureProfile profile = new AzureProfile(AzureEnvironment.AZURE);
56+
57+
// create a policy for setting user token into a specific header for some special scenarios
58+
HttpPipelinePolicy userTokenPolicy = new UserTokenPolicy(credential, profile.getEnvironment());
59+
60+
// build resource manager to create azure resource
61+
AzureResourceManager azureResourceManager = AzureResourceManager.authenticate(credential, profile).withDefaultSubscription();
62+
ServiceLinkerManager serviceLinkerManager = ServiceLinkerManager.authenticate(credential, profile);
63+
ServiceLinkerManager serviceLinkerManagerWithUserToken = ServiceLinkerManager.configure().withPolicy(userTokenPolicy).authenticate(credential, profile);
64+
65+
createSpringCloudAndSQLConnection(azureResourceManager, serviceLinkerManager);
66+
67+
// for KeyVault/SecretStore/VirtualNetwork scenario, it needs user token in header for creating connection
68+
createWebAppAndKeyVaultConnectionWithUserIdentity(azureResourceManager, serviceLinkerManagerWithUserToken);
69+
}
70+
71+
private static void createSpringCloudAndSQLConnection(AzureResourceManager azureResourceManager, ServiceLinkerManager serviceLinkerManager) {
72+
String resourceGroupName = "rg" + randomString(8);
73+
Region region = Region.US_EAST;
74+
String springServiceName = "spring" + randomString(8);
75+
String springAppName = "app" + randomString(8);
76+
String sqlServerName = "sqlserver" + randomString(8);
77+
String sqlDatabaseName = "sqldb" + randomString(8);
78+
String sqlUserName = "sql" + randomString(8);
79+
String sqlPassword = "5$Ql" + randomString(8);
80+
81+
SpringService springService = azureResourceManager.springServices().define(springServiceName)
82+
.withRegion(region)
83+
.withNewResourceGroup(resourceGroupName)
84+
.withSku(SkuName.B0)
85+
.create();
86+
87+
SpringApp springApp = springService.apps().define(springAppName)
88+
.withDefaultActiveDeployment()
89+
.create();
90+
91+
SqlServer sqlServer = azureResourceManager.sqlServers().define(sqlServerName)
92+
.withRegion(region)
93+
.withExistingResourceGroup(resourceGroupName)
94+
.withAdministratorLogin(sqlUserName)
95+
.withAdministratorPassword(sqlPassword)
96+
.create();
97+
98+
SqlDatabase sqlDatabase = sqlServer.databases().define(sqlDatabaseName)
99+
.withBasicEdition()
100+
.create();
101+
102+
LinkerResource linker = serviceLinkerManager.linkers().define("sql")
103+
.withExistingResourceUri(springApp.getActiveDeployment().id())
104+
.withTargetService(
105+
new AzureResource()
106+
.withId(sqlDatabase.id())
107+
)
108+
.withAuthInfo(
109+
new SecretAuthInfo()
110+
.withName(sqlUserName)
111+
.withSecretInfo(
112+
new ValueSecretInfo()
113+
.withValue(sqlPassword)
114+
)
115+
)
116+
.withClientType(ClientType.SPRING_BOOT)
117+
.create();
118+
119+
System.out.println("Configurations:");
120+
for (SourceConfiguration sourceConfiguration : linker.listConfigurations().configurations()) {
121+
System.out.printf("\t%s: %s%n", sourceConfiguration.name(), sourceConfiguration.value());
122+
}
123+
}
124+
125+
private static void createWebAppAndKeyVaultConnectionWithUserIdentity(AzureResourceManager azureResourceManager, ServiceLinkerManager serviceLinkerManager) {
126+
String resourceGroupName = "rg" + randomString(8);
127+
Region region = Region.US_EAST;
128+
String webAppName = "web" + randomString(8);
129+
String keyVaultName = "vault" + randomString(8);
130+
String identityName = "identity" + randomString(8);
131+
132+
WebApp webApp = azureResourceManager.webApps().define(webAppName)
133+
.withRegion(region)
134+
.withNewResourceGroup(resourceGroupName)
135+
.withNewLinuxPlan(PricingTier.BASIC_B1)
136+
.withBuiltInImage(RuntimeStack.NODEJS_14_LTS)
137+
.create();
138+
139+
Vault vault = azureResourceManager.vaults().define(keyVaultName)
140+
.withRegion(region)
141+
.withExistingResourceGroup(resourceGroupName)
142+
.withEmptyAccessPolicy()
143+
.create();
144+
145+
Identity identity = azureResourceManager.identities().define(identityName)
146+
.withRegion(region)
147+
.withExistingResourceGroup(resourceGroupName)
148+
.create();
149+
150+
LinkerResource linker = serviceLinkerManager.linkers().define("keyvault")
151+
.withExistingResourceUri(webApp.id())
152+
.withTargetService(
153+
new AzureResource()
154+
.withId(vault.id())
155+
)
156+
.withAuthInfo(
157+
new UserAssignedIdentityAuthInfo()
158+
.withSubscriptionId(azureResourceManager.subscriptionId())
159+
.withClientId(identity.clientId())
160+
)
161+
.withClientType(ClientType.NODEJS)
162+
.create();
163+
164+
System.out.println("Configurations:");
165+
for (SourceConfiguration sourceConfiguration : linker.listConfigurations().configurations()) {
166+
System.out.printf("\t%s: %s%n", sourceConfiguration.name(), sourceConfiguration.value());
167+
}
168+
}
169+
170+
private static String randomString(int length) {
171+
return UUID.randomUUID().toString().replace("-", "").substring(0, length);
172+
}
173+
174+
public static class UserTokenPolicy implements HttpPipelinePolicy {
175+
private final TokenCredential credential;
176+
private final AzureEnvironment environment;
177+
178+
public UserTokenPolicy(TokenCredential credential, AzureEnvironment environment) {
179+
this.credential = credential;
180+
this.environment = environment;
181+
}
182+
183+
@Override
184+
public Mono<HttpResponse> process(HttpPipelineCallContext context, HttpPipelineNextPolicy next) {
185+
Mono<String> token = null;
186+
String bearerTokenPrefix = "bearer ";
187+
String authorization = context.getHttpRequest().getHeaders().getValue("Authorization");
188+
if (authorization != null && authorization.toLowerCase(Locale.ROOT).startsWith(bearerTokenPrefix)) {
189+
token = Mono.just(authorization.substring(bearerTokenPrefix.length()));
190+
} else {
191+
token = credential
192+
.getToken(new TokenRequestContext().addScopes(environment.getResourceManagerEndpoint() + "/.default"))
193+
.map(AccessToken::getToken);
194+
}
195+
196+
return token
197+
.flatMap(accessToken -> {
198+
context.getHttpRequest().getHeaders().set(USER_TOKEN_HEADER, accessToken);
199+
return next.process();
200+
});
201+
}
202+
}
203+
}

0 commit comments

Comments
 (0)