Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
d520c9c
add integration tests for aad, keyvault and cosmosdb
saragluna May 29, 2020
a7ad271
fix tests.yml
saragluna May 29, 2020
f2cbd11
test for keyvault with vm
saragluna May 29, 2020
f4d76ed
fix enforcer
saragluna Jun 1, 2020
cd94a0c
apply pr: Deliver multiple KeyVault support
yiliuTo May 28, 2020
337c2df
migrate pr: cache key vault values
yiliuTo May 28, 2020
4aa812a
migrate pr: keyvault case sensitive names
yiliuTo May 28, 2020
1f2dadf
multiKeyvaultIT
yiliuTo Jun 1, 2020
2f55a36
export VM resources for keyvaultIT
yiliuTo Jun 1, 2020
a8a748e
ignore keyvaultIT of vmMSI
yiliuTo Jun 1, 2020
6c94117
modify versions and remove dependencymanagement
yiliuTo Jun 5, 2020
a263983
add readme.md for pipeline check
yiliuTo Jun 8, 2020
2b6efa1
add external dependencies
yiliuTo Jun 8, 2020
f3b69ff
add dependency for test-core
yiliuTo Jun 8, 2020
43406f8
exclude integration tests in CI pipeline
yiliuTo Jun 9, 2020
6687cb8
add environment var on CI to skip IT
yiliuTo Jun 10, 2020
238d58a
add property for skipSpringITs
saragluna Jun 11, 2020
f7da5de
Merge pull request #5 from saragluna/feature/migrate-multiKeyvaultIT
yiliuTo Jun 11, 2020
f5f8793
refine dependencies
saragluna Jun 11, 2020
8c56435
fix dependencies issue
saragluna Jun 11, 2020
d11c9bc
rename packages
saragluna Jun 11, 2020
96da1f3
add spring code owners
saragluna Jun 11, 2020
b0848e6
Merge pull request #6 from saragluna/feature/migrate-multiKeyvaultIT
yiliuTo Jun 11, 2020
444c32b
include a starter in test-core, to make it included when build from s…
saragluna Jun 11, 2020
956e3be
Merge pull request #7 from saragluna/feature/migrate-multiKeyvaultIT
yiliuTo Jun 11, 2020
9d5708d
remove the matrix overriding in tests.yml
saragluna Jun 12, 2020
3422e53
Merge pull request #8 from saragluna/feature/migrate-multiKeyvaultIT
yiliuTo Jun 12, 2020
646d222
Merge branch 'master' into feature/migrate-multiKeyvaultIT
saragluna Jun 12, 2020
4189114
remove MaxParallel parameter in spring tests.yml
saragluna Jun 13, 2020
538793c
Merge pull request #9 from saragluna/feature/migrate-multiKeyvaultIT
yiliuTo Jun 13, 2020
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
/sdk/servicebus/ @yvgopal @nemakam @hemanttanwar @conniey
/sdk/storage/ @amishra-dev @rickle-msft @jaschrep-msft @gapra-msft @alzimmermsft @sima-zhu
/sdk/textanalytics/ @samvaity @mssfang @sima-zhu
/sdk/spring/ @saragluna @yiliuTo @chenrujun @jialindai

# end to end tests
/sdk/e2e/ @jianghaolu @g2vinay
Expand Down
12 changes: 12 additions & 0 deletions eng/versioning/external_dependencies.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,10 @@ pl.pragmatists:JUnitParams;1.1.1

## Test dependency versions
cglib:cglib-nodep;3.2.7
com.alibaba:fastjson;1.2.61
com.github.cverges.expect4j:expect4j;1.6
com.github.tomakehurst:wiremock-standalone;2.24.1
com.jcraft:jsch;0.1.53
com.microsoft.azure:adal4j;1.6.5
com.microsoft.azure:azure;1.24.1
com.microsoft.azure:azure-mgmt-graph-rbac;1.3.0
Expand All @@ -98,8 +101,14 @@ io.opentelemetry:opentelemetry-api;0.2.4
io.opentelemetry:opentelemetry-sdk;0.2.4
io.projectreactor:reactor-test;3.3.5.RELEASE
junit:junit;4.13-beta-3
org.apache.maven:maven-compat;3.6.2
org.apache.maven:maven-embedder;3.6.2
org.apache.maven.wagon:wagon-http;3.3.4
org.apache.maven.wagon:wagon-provider-api;3.3.4
org.assertj:assertj-core;3.11.1
org.bouncycastle:bcprov-jdk15on;1.60
org.eclipse.aether:aether-connector-basic;1.1.0
org.eclipse.aether:aether-transport-wagon;1.1.0
org.eclipse.jetty:jetty-http;9.4.11.v20180605
org.eclipse.jetty:jetty-server;9.4.11.v20180605
org.hamcrest:hamcrest-all;1.3
Expand All @@ -125,6 +134,8 @@ org.junit.platform:junit-platform-testkit;1.6.2
org.junit.vintage:junit-vintage-engine;5.6.2
org.openjdk.jmh:jmh-core;1.22
org.openjdk.jmh:jmh-generator-annprocess;1.22
org.springframework.boot:spring-boot;2.2.0.RELEASE
org.springframework:spring-context;5.2.0.RELEASE
org.spockframework:spock-core;1.3-groovy-2.5
org.testng:testng;6.14.3
uk.org.lidalia:slf4j-test;1.2.0
Expand Down Expand Up @@ -238,3 +249,4 @@ storage_com.microsoft.azure:azure-storage;8.4.0
# sdk\spring\azure-spring-boot\pom.xml
spring_io.micrometer:micrometer-core;1.3.0
spring_io.micrometer:micrometer-registry-azure-monitor;1.3.0
spring_com.microsoft.azure:azure;1.34.0
3 changes: 3 additions & 0 deletions eng/versioning/version_client.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ com.microsoft.azure:azure-data-gremlin-spring-boot-starter;2.2.4;2.2.5-beta.1
com.microsoft.azure:azure-keyvault-secrets-spring-boot-starter;2.2.4;2.2.5-beta.1
com.microsoft.azure:azure-servicebus-jms-spring-boot-starter;2.2.4;2.2.5-beta.1
com.microsoft.azure:azure-spring-boot-metrics-starter;2.2.4;2.2.5-beta.1
com.microsoft.azure:azure-spring-boot-tests;2.2.4;2.2.5-beta.1
com.microsoft.azure:azure-spring-boot-test-core;2.2.4;2.2.5-beta.1


# Unreleased dependencies: Copy the entry from above, prepend "unreleased_" and remove the current
# version. Unreleased dependencies are only valid for dependency versions.
Expand Down
56 changes: 56 additions & 0 deletions sdk/spring/azure-spring-boot-starter-keyvault-secrets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,62 @@ azure.keyvault.allow.telemetry=false
When telemetry is enabled, an HTTP request will be sent to URL `https://dc.services.visualstudio.com/v2/track`. So please make sure it's not blocked by your firewall.
Find more information about Azure Service Privacy Statement, please check [Microsoft Online Services Privacy Statement](https://www.microsoft.com/privacystatement/OnlineServices/Default.aspx).

## Multiple Key Vault support

If you want to use multiple key vaults you need to define names for each of the
key vaults you want to use and in which order the key vaults should be consulted.
If a property exists in multiple key vaults the order determine which value you
will get back.

The example below shows a setup for 2 key vaults, named `keyvault1` and
`keyvault2`. The order specifies that `keyvault1` will be consulted first.

```
azure.keyvault.order=keyvault1,keyvault2
azure.keyvault.keyvault1.uri=put-a-azure-keyvault-uri-here
azure.keyvault.keyvault1.client-id=put-a-azure-client-id-here
azure.keyvault.keyvault1.client-key=put-a-azure-client-key-here
azure.keyvault.keyvault1.tenant-id=put-a-azure-tenant-id-here
azure.keyvault.keyvault2.uri=put-a-azure-keyvault-uri-here
azure.keyvault.keyvault2.client-id=put-a-azure-client-id-here
azure.keyvault.keyvault2.client-key=put-a-azure-client-key-here
azure.keyvault.keyvault2.tenant-id=put-a-azure-tenant-id-here
```

Note if you decide to use multiple key vault support and you already have an
existing configuration, please make sure you migrate that configuration to the
multiple key vault variant. Mixing multiple key vaults with an existing single
key vault configuration is a non supported scenario.

## Case sensitive key mode

The new case sensitive mode allows you to use case sensitive key vault names. Note
that the key vault secret key still needs to honor the naming limitation as
described in [About keys, secrets, and certificates](https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates).

To enable case sensitive mode use:

```
azure.keyvault.case-sensitive-keys=true
```

## Placeholders in properties

If your Spring property is using a name that does not honor the key vault secret
key limitation use the following technique as described by
[Externalized Configuration](https://docs.spring.io/autorepo/docs/spring-boot/2.2.7.RELEASE/reference/html/spring-boot-features.html#boot-features-external-config-placeholders-in-properties)
in the Spring Boot documentation.

An example of using a placeholder:

```
my.not.compliant.property=${myCompliantKeyVaultSecret}
```

The application will take care of getting the value that is backed by the
`myCompliantKeyVaultSecret` key name and assign its value to the non compliant
`my.not.compliant.property`.

## Troubleshooting
## Next steps
## Contributing
18 changes: 18 additions & 0 deletions sdk/spring/azure-spring-boot-tests/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#Azure Spring Boot Integration tests client library for Java

## Key concepts
The structure of integration tests are organized as:

- azure-spring-boot-tests (top folder for integration tests)
- azure-spring-boot-test-core (common code shared by integration tests)
- azure-spring-boot-test-keyvault (integration tests for key vault starter)
- azure-spring-boot-test-aad (integration tests for aad starter)
- azure-spring-boot-test-cosmosdb (integration tests for cosmos starter)
- azure-spring-boot-test-application (an application used by other integration tests)

## Getting started
## Key concepts
## Examples
## Troubleshooting
## Next steps
## Contributing
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
<?xml version="1.0" encoding="UTF-8"?>
<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">
<parent>
<artifactId>azure-spring-boot-tests</artifactId>
<groupId>com.microsoft.azure</groupId>
<version>2.2.5-beta.1</version> <!-- {x-version-update;com.microsoft.azure:azure-spring-boot-tests;current} -->
<relativePath>../pom.xml</relativePath>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>azure-spring-boot-test-aad</artifactId>

<dependencies>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-spring-boot-test-core</artifactId>
<version>2.2.5-beta.1</version> <!-- {x-version-update;com.microsoft.azure:azure-spring-boot-test-core;current} -->
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-active-directory-spring-boot-starter</artifactId>
<version>2.2.5-beta.1</version> <!-- {x-version-update;com.microsoft.azure:azure-active-directory-spring-boot-starter;current} -->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<version>2.2.0.RELEASE</version> <!-- {x-version-update;org.springframework.boot:spring-boot-starter-test;external_dependency} -->
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>3.0.0-M3</version> <!-- {x-version-update;org.apache.maven.plugins:maven-enforcer-plugin;external_dependency} -->
<configuration>
<rules>
<bannedDependencies>
<includes>
<include>com.microsoft.azure:*</include>
<include>org.springframework.boot:spring-boot-starter-web:[2.2.0.RELEASE]</include> <!-- {x-include-update;org.springframework.boot:spring-boot-starter-web;external_dependency} -->
</includes>
</bannedDependencies>
</rules>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.0</version> <!-- {x-version-update;org.apache.maven.plugins:maven-failsafe-plugin;external_dependency} -->
<configuration>
<skipITs>${skipSpringITs}</skipITs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

package com.microsoft.azure.test.keyvault.approle;

import com.microsoft.azure.spring.autoconfigure.aad.AADAppRoleStatelessAuthenticationFilter;
import com.microsoft.azure.test.utils.AppRunner;
import com.microsoft.azure.test.oauth.OAuthResponse;
import com.microsoft.azure.test.oauth.OAuthUtils;
import org.junit.Ignore;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.util.HashMap;

import static com.microsoft.azure.test.oauth.OAuthUtils.AAD_CLIENT_ID;
import static com.microsoft.azure.test.oauth.OAuthUtils.AAD_CLIENT_SECRET;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;

public class AADAppRoleStatelessAuthenticationFilterIT {

private static final Logger LOGGER = LoggerFactory.getLogger(AADAppRoleStatelessAuthenticationFilterIT.class);
private final RestTemplate restTemplate = new RestTemplate();

@Test
@Ignore
public void testAADAppRoleStatelessAuthenticationFilter() {
final OAuthResponse authResponse = OAuthUtils.executeOAuth2ROPCFlow(System.getenv(AAD_CLIENT_ID),
System.getenv(AAD_CLIENT_SECRET));
assertNotNull(authResponse);

try (AppRunner app = new AppRunner(DumbApp.class)) {

app.property("azure.activedirectory.client-id", System.getenv(AAD_CLIENT_ID));
app.property("azure.activedirectory.session-stateless", "true");

app.start();

final ResponseEntity<String> response = restTemplate.exchange(app.root() + "public",
HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), String.class, new HashMap<>());
assertEquals(HttpStatus.OK, response.getStatusCode());
assertEquals("public endpoint response", response.getBody());

try {
restTemplate.exchange(app.root() + "authorized",
HttpMethod.GET, new HttpEntity<>(new HttpHeaders()), String.class, new HashMap<>());
} catch (Exception e) {
assertEquals(HttpClientErrorException.Forbidden.class, e.getClass());
}

final HttpHeaders headers = new HttpHeaders();
headers.set("Authorization", String.format("Bearer %s", authResponse.getIdToken()));
final HttpEntity<Object> entity = new HttpEntity<>(headers);

final ResponseEntity<String> response2 = restTemplate.exchange(app.root() + "authorized",
HttpMethod.GET, entity, String.class, new HashMap<>());
assertEquals(HttpStatus.OK, response2.getStatusCode());
assertEquals("authorized endpoint response", response2.getBody());

final ResponseEntity<String> response3 = restTemplate.exchange(app.root() + "admin/demo",
HttpMethod.GET, entity, String.class, new HashMap<>());
assertEquals(HttpStatus.OK, response3.getStatusCode());
assertEquals("admin endpoint response", response3.getBody());

LOGGER.info("--------------------->test over");
}
}

@EnableGlobalMethodSecurity(prePostEnabled = true)
@SpringBootApplication
@RestController
public static class DumbApp extends WebSecurityConfigurerAdapter {

@Autowired
private AADAppRoleStatelessAuthenticationFilter aadAuthFilter;

@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();

http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER);

http.authorizeRequests()
.antMatchers("/admin/**").hasRole("Admin")
.antMatchers("/", "/index.html", "/public").permitAll()
.anyRequest().authenticated();

http.addFilterBefore(aadAuthFilter, UsernamePasswordAuthenticationFilter.class);
}

@GetMapping("/public")
public String publicMethod() {
return "public endpoint response";
}

@GetMapping("/authorized")
@PreAuthorize("hasRole('ROLE_User')")
public String onlyAuthorizedUsers() {
return "authorized endpoint response";
}

@GetMapping("/admin/demo")
public String onlyForAdmins() {
return "admin endpoint response";
}
}

}
Loading