1313package tech .pegasys .web3signer .tests .bulkloading ;
1414
1515import static org .assertj .core .api .Assertions .assertThat ;
16+ import static org .hamcrest .Matchers .containsInAnyOrder ;
1617import static org .hamcrest .Matchers .equalTo ;
17- import static org .hamcrest .Matchers .hasItems ;
1818import static org .hamcrest .Matchers .hasSize ;
1919import static org .junit .jupiter .api .Assumptions .assumeTrue ;
2020import static tech .pegasys .web3signer .core .config .HealthCheckNames .KEYS_CHECK_AZURE_BULK_LOADING ;
2121import static tech .pegasys .web3signer .dsl .utils .HealthCheckResultUtil .getHealtcheckKeysLoaded ;
2222import static tech .pegasys .web3signer .dsl .utils .HealthCheckResultUtil .getHealthcheckErrorCount ;
23+ import static tech .pegasys .web3signer .keystorage .azure .AzureKeyVault .createUsingClientSecretCredentials ;
2324
25+ import tech .pegasys .teku .bls .BLSSecretKey ;
2426import tech .pegasys .web3signer .dsl .signer .SignerConfigurationBuilder ;
27+ import tech .pegasys .web3signer .keystorage .azure .AzureKeyVault ;
2528import tech .pegasys .web3signer .signing .KeyType ;
2629import tech .pegasys .web3signer .signing .config .AzureKeyVaultParameters ;
2730import tech .pegasys .web3signer .signing .config .DefaultAzureKeyVaultParameters ;
2831import tech .pegasys .web3signer .tests .AcceptanceTestBase ;
2932
33+ import java .util .List ;
3034import java .util .Map ;
31- import java .util .stream .Stream ;
35+ import java .util .concurrent .ExecutorService ;
36+ import java .util .concurrent .Executors ;
3237
33- import com .fasterxml . jackson . core . JsonProcessingException ;
38+ import com .google . common . annotations . VisibleForTesting ;
3439import io .restassured .http .ContentType ;
3540import io .restassured .response .Response ;
3641import org .apache .commons .lang3 .StringUtils ;
42+ import org .apache .tuweni .bytes .Bytes32 ;
3743import org .junit .jupiter .api .BeforeAll ;
3844import org .junit .jupiter .params .ParameterizedTest ;
39- import org .junit .jupiter .params .provider .Arguments ;
4045import org .junit .jupiter .params .provider .EnumSource ;
41- import org .junit .jupiter .params .provider .MethodSource ;
4246
4347public class AzureKeyVaultAcceptanceTest extends AcceptanceTestBase {
4448
4549 private static final String CLIENT_ID = System .getenv ("AZURE_CLIENT_ID" );
4650 private static final String CLIENT_SECRET = System .getenv ("AZURE_CLIENT_SECRET" );
4751 private static final String TENANT_ID = System .getenv ("AZURE_TENANT_ID" );
4852 private static final String VAULT_NAME = System .getenv ("AZURE_KEY_VAULT_NAME" );
49- private static final String BLS_KEY =
50- "0x989d34725a2bfc3f15105f3f5fc8741f436c25ee1ee4f948e425d6bcb8c56bce6e06c269635b7e985a7ffa639e2409bf" ;
51- private static final String BLS_TAGGED_KEY =
52- "0xb3b6fb8dab2a4c9d00247c18c4b7e91c62da3f7ad31c822c00097f93ac8ff2c4a526611f7d0a9c85946e93f371852c69" ;
53- private static final String SECP_KEY =
54- "0xa95663509e608da3c2af5a48eb4315321f8430cbed5518a44590cc9d367f01dc72ebbc583fc7d94f9fdc20eb6e162c9f8cb35be8a91a3b1d32a63ecc10be4e08" ;
55- private static final String SECP_TAGGED_KEY =
56- "0x234053dbe014ebe573e5e8f6eab5e0417bf705466009f7c15b8d23593abd1bda426593d92b32efb240afe6efa46d5679fad0dc427e0aa0fc61c2464ce93c7c5e" ;
5753
5854 @ BeforeAll
5955 public static void setup () {
@@ -63,10 +59,84 @@ public static void setup() {
6359 assumeTrue (!StringUtils .isEmpty (VAULT_NAME ), "Set AZURE_KEY_VAULT_NAME environment variable" );
6460 }
6561
62+ /**
63+ * These keys are expected to be pre-created in Azure keystore. The first secret is multivalue
64+ * with 10 keys. The second secret is created with single value/key and tagged with ENV:TEST.
65+ *
66+ * @return list of expected BLS public keys in hex format
67+ */
68+ static List <String > expectedBLSPubKeys () {
69+ return getBLSSecretsFromAzureVault ().stream ()
70+ .flatMap (azureSecret -> azureSecret .values ().stream ())
71+ .map (
72+ secret ->
73+ BLSSecretKey .fromBytes (Bytes32 .fromHexString (secret )).toPublicKey ().toHexString ())
74+ .toList ();
75+ }
76+
77+ static List <String > expectedBLSPubKeyWithTag (final String tagKey , final String tagValue ) {
78+ return getBLSSecretsFromAzureVault ().stream ()
79+ .filter (
80+ azureSecret ->
81+ azureSecret .tags () != null
82+ && azureSecret .tags ().containsKey (tagKey )
83+ && azureSecret .tags ().get (tagKey ).equals (tagValue ))
84+ .flatMap (azureSecret -> azureSecret .values ().stream ())
85+ .map (
86+ secret ->
87+ BLSSecretKey .fromBytes (Bytes32 .fromHexString (secret )).toPublicKey ().toHexString ())
88+ .toList ();
89+ }
90+
91+ /**
92+ * Expected SECP256K1 public keys pre-created in Azure keystore.
93+ *
94+ * @return list of expected SECP256K1 public keys in hex format
95+ */
96+ static List <String > expectedSECPPubKeys () {
97+ return getSECPKeysFromAzureVault ().stream ().map (AzureKeyVault .AzureKey ::publicKeyHex ).toList ();
98+ }
99+
100+ static List <String > expectedSECPPubKeyWithTag (final String tagKey , final String tagValue ) {
101+ return getSECPKeysFromAzureVault ().stream ()
102+ .filter (
103+ azureSecret ->
104+ azureSecret .tags () != null
105+ && azureSecret .tags ().containsKey (tagKey )
106+ && azureSecret .tags ().get (tagKey ).equals (tagValue ))
107+ .map (AzureKeyVault .AzureKey ::publicKeyHex )
108+ .toList ();
109+ }
110+
111+ @ VisibleForTesting
112+ public static List <AzureKeyVault .AzureKey > getSECPKeysFromAzureVault () {
113+ try (ExecutorService executor = Executors .newVirtualThreadPerTaskExecutor ()) {
114+ final AzureKeyVault azureKeyVault =
115+ createUsingClientSecretCredentials (
116+ CLIENT_ID , CLIENT_SECRET , TENANT_ID , VAULT_NAME , executor , 60 );
117+
118+ final var azureKeys = azureKeyVault .getAzureKeys ();
119+ assertThat (azureKeys ).isNotEmpty ();
120+ return azureKeys ;
121+ }
122+ }
123+
124+ public static List <AzureKeyVault .AzureSecret > getBLSSecretsFromAzureVault () {
125+ try (ExecutorService executor = Executors .newVirtualThreadPerTaskExecutor ()) {
126+ final AzureKeyVault azureKeyVault =
127+ createUsingClientSecretCredentials (
128+ CLIENT_ID , CLIENT_SECRET , TENANT_ID , VAULT_NAME , executor , 60 );
129+
130+ return azureKeyVault .getAzureSecrets ();
131+ }
132+ }
133+
66134 @ ParameterizedTest
67135 @ EnumSource (KeyType .class )
68- void ensureSecretsInKeyVaultAreLoadedAndReportedViaPublicKeysApi (final KeyType keyType )
69- throws JsonProcessingException {
136+ void ensureSecretsInKeyVaultAreLoadedAndReportedViaPublicKeysApi (final KeyType keyType ) {
137+ final List <String > expectedPubKeys =
138+ keyType == KeyType .BLS ? expectedBLSPubKeys () : expectedSECPPubKeys ();
139+
70140 final AzureKeyVaultParameters azureParams =
71141 new DefaultAzureKeyVaultParameters (VAULT_NAME , CLIENT_ID , TENANT_ID , CLIENT_SECRET );
72142
@@ -83,7 +153,7 @@ void ensureSecretsInKeyVaultAreLoadedAndReportedViaPublicKeysApi(final KeyType k
83153 .then ()
84154 .statusCode (200 )
85155 .contentType (ContentType .JSON )
86- .body ("" , hasItems ( expectedKey ( keyType , false )));
156+ .body ("" , containsInAnyOrder ( expectedPubKeys . toArray ( )));
87157
88158 final Response healthcheckResponse = signer .healthcheck ();
89159 healthcheckResponse
@@ -92,36 +162,36 @@ void ensureSecretsInKeyVaultAreLoadedAndReportedViaPublicKeysApi(final KeyType k
92162 .contentType (ContentType .JSON )
93163 .body ("status" , equalTo ("UP" ));
94164
95- // BLS keys include additional multi-line key with 200 keys
96- final int expectedKeyLoaded = keyType == KeyType .BLS ? 202 : 2 ;
97-
98165 final String jsonBody = healthcheckResponse .body ().asString ();
99166 final int keysLoaded = getHealtcheckKeysLoaded (jsonBody , KEYS_CHECK_AZURE_BULK_LOADING );
100- assertThat (keysLoaded ).isEqualTo (expectedKeyLoaded );
167+ assertThat (keysLoaded ).isEqualTo (expectedPubKeys . size () );
101168 }
102169
103- @ ParameterizedTest (name = "{index} - KeyType: {0}, using config file: {1} " )
104- @ MethodSource ( "azureSecretsViaTag" )
105- void azureSecretsViaTag (final KeyType keyType , boolean useConfigFile ) {
170+ @ ParameterizedTest (name = "{index} - KeyType: {0}" )
171+ @ EnumSource ( KeyType . class )
172+ void azureSecretsViaTag (final KeyType keyType ) {
106173 final AzureKeyVaultParameters azureParams =
107174 new DefaultAzureKeyVaultParameters (
108175 VAULT_NAME , CLIENT_ID , TENANT_ID , CLIENT_SECRET , Map .of ("ENV" , "TEST" ));
109176
110177 final SignerConfigurationBuilder configBuilder =
111178 new SignerConfigurationBuilder ()
112179 .withMode (calculateMode (keyType ))
113- .withUseConfigFile (useConfigFile )
114180 .withAzureKeyVaultParameters (azureParams )
115181 .withUseConfigFile (true );
116182
117183 startSigner (configBuilder .build ());
118184
185+ final List <String > expectedPubKey =
186+ keyType == KeyType .BLS
187+ ? expectedBLSPubKeyWithTag ("ENV" , "TEST" )
188+ : expectedSECPPubKeyWithTag ("ENV" , "TEST" );
119189 final Response response = signer .callApiPublicKeys (keyType );
120190 response
121191 .then ()
122192 .statusCode (200 )
123193 .contentType (ContentType .JSON )
124- .body ("" , hasItems ( expectedKey ( keyType , true )));
194+ .body ("" , containsInAnyOrder ( expectedPubKey . toArray ( )));
125195
126196 // the tag filter will return only valid keys. The healthcheck should be UP
127197 final Response healthcheckResponse = signer .healthcheck ();
@@ -131,22 +201,14 @@ void azureSecretsViaTag(final KeyType keyType, boolean useConfigFile) {
131201 .contentType (ContentType .JSON )
132202 .body ("status" , equalTo ("UP" ));
133203
134- // keys loaded should be 1 as well.
204+ // keys loaded should be >= 1 and error count should be 0
135205 final String jsonBody = healthcheckResponse .body ().asString ();
136206 final int keysLoaded = getHealtcheckKeysLoaded (jsonBody , KEYS_CHECK_AZURE_BULK_LOADING );
137207 final int errorCount = getHealthcheckErrorCount (jsonBody , KEYS_CHECK_AZURE_BULK_LOADING );
138- assertThat (keysLoaded ).isOne ();
208+ assertThat (keysLoaded ).isNotZero ();
139209 assertThat (errorCount ).isZero ();
140210 }
141211
142- private static Stream <Arguments > azureSecretsViaTag () {
143- return Stream .of (
144- Arguments .arguments (KeyType .BLS , false ),
145- Arguments .arguments (KeyType .BLS , true ),
146- Arguments .arguments (KeyType .SECP256K1 , false ),
147- Arguments .arguments (KeyType .SECP256K1 , true ));
148- }
149-
150212 @ ParameterizedTest
151213 @ EnumSource (KeyType .class )
152214 void invalidVaultParametersFailsToLoadKeys (final KeyType keyType ) {
@@ -194,16 +256,12 @@ void envVarsAreUsedToDefaultAzureParams(final KeyType keyType) {
194256 startSigner (configBuilder .build ());
195257
196258 final Response response = signer .callApiPublicKeys (keyType );
259+ final List <String > expectedPubKeys =
260+ keyType == KeyType .BLS ? expectedBLSPubKeys () : expectedSECPPubKeys ();
197261 response
198262 .then ()
199263 .statusCode (200 )
200264 .contentType (ContentType .JSON )
201- .body ("" , hasItems (expectedKey (keyType , false )));
202- }
203-
204- private String expectedKey (final KeyType keyType , final boolean tagged ) {
205- return keyType == KeyType .BLS
206- ? tagged ? BLS_TAGGED_KEY : BLS_KEY
207- : tagged ? SECP_TAGGED_KEY : SECP_KEY ;
265+ .body ("" , containsInAnyOrder (expectedPubKeys .toArray ()));
208266 }
209267}
0 commit comments