From fc7d340a898ce44f3f1f093f480c8356a195a56f Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 7 May 2021 12:51:01 +0000 Subject: [PATCH 1/5] Query to detect hard-coded Azure credentials --- .../CWE-798/HardcodedAzureCredentials.java | 52 ++++++ .../CWE-798/HardcodedCredentialsApiCall.qhelp | 30 ++++ .../src/Security/CWE/CWE-798/SensitiveApi.qll | 10 +- .../tests/HardcodedAzureCredentials.java | 66 ++++++++ .../HardcodedCredentialsApiCall.expected | 37 +++++ .../HardcodedCredentialsSourceCall.expected | 28 ++++ .../security/CWE-798/semmle/tests/options | 2 +- .../core/credential/TokenCredential.java | 10 ++ .../identity/AadCredentialBuilderBase.java | 43 +++++ .../identity/ClientSecretCredential.java | 18 ++ .../ClientSecretCredentialBuilder.java | 63 +++++++ .../azure/identity/CredentialBuilderBase.java | 13 ++ .../TokenCachePersistenceOptions.java | 48 ++++++ .../identity/UsernamePasswordCredential.java | 14 ++ .../UsernamePasswordCredentialBuilder.java | 74 +++++++++ .../keyvault/secrets/SecretClient.java | 155 ++++++++++++++++++ .../keyvault/secrets/SecretClientBuilder.java | 92 +++++++++++ .../secrets/models/KeyVaultSecret.java | 78 +++++++++ .../secrets/models/SecretProperties.java | 145 ++++++++++++++++ 19 files changed, 974 insertions(+), 4 deletions(-) create mode 100644 java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java create mode 100644 java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAzureCredentials.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/core/credential/TokenCredential.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/AadCredentialBuilderBase.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredential.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredentialBuilder.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/CredentialBuilderBase.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/TokenCachePersistenceOptions.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredential.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredentialBuilder.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClient.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClientBuilder.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/KeyVaultSecret.java create mode 100644 java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/SecretProperties.java diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java b/java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java new file mode 100644 index 00000000000..a8b52aa43a1 --- /dev/null +++ b/java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java @@ -0,0 +1,52 @@ +public class HardcodedAzureCredentials { + private final String clientId = "81734019-15a3-50t8-3253-5abe78abc3a1"; + private final String username = "username@example.onmicrosoft.com"; + private final String clientSecret = "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_"; + private final String tenantId = "22f367ce-535x-357w-2179-a33517mn166h"; + + //BAD: hard-coded username/password credentials + public void testHardcodedUsernamePassword(String input) { + UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredentialBuilder() + .clientId(clientId) + .username(username) + .password(clientSecret) + .build(); + + SecretClient client = new SecretClientBuilder() + .vaultUrl("https://myKeyVault.vault.azure.net") + .credential(usernamePasswordCredential) + .buildClient(); + } + + //GOOD: username/password credentials stored as environment variables + public void testEnvironmentUsernamePassword(String input) { + UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredentialBuilder() + .clientId(clientId) + .username(System.getenv("myUsername")) + .password(System.getenv("mySuperSecurePass")) + .build(); + + SecretClient client = new SecretClientBuilder() + .vaultUrl("https://myKeyVault.vault.azure.net") + .credential(usernamePasswordCredential) + .buildClient(); + } + + //BAD: hard-coded client secret + public void testHardcodedClientSecret(String input) { + ClientSecretCredential defaultCredential = new ClientSecretCredentialBuilder() + .clientId(clientId) + .clientSecret(clientSecret) + .tenantId(tenantId) + .build(); + } + + //GOOD: client secret stored as environment variables + public void testEnvironmentClientSecret(String input) { + ClientSecretCredential defaultCredential = new ClientSecretCredentialBuilder() + .clientId(clientId) + .clientSecret(System.getenv("myClientSecret")) + .tenantId(tenantId) + .build(); + } +} \ No newline at end of file diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp index 231140a287e..efcf6b15abf 100644 --- a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp +++ b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp @@ -32,6 +32,28 @@ Instead, the user name and password could be supplied through environment variables, which can be set externally without hard-coding credentials in the source code.

+ +

+ The following code example connects to AWS using a hard-coded access key ID and secret key: +

+ + + +

+ Instead, the access key ID and secret key could be supplied through environment variables, + which can be set externally without hard-coding credentials in the source code. +

+ +

+ The following code example connects to Azure using a hard-coded user name and password or client secret: +

+ + + +

+ Instead, the username and password or client secret could be supplied through environment variables, + which can be set externally without hard-coding credentials in the source code. +

@@ -39,6 +61,14 @@ OWASP: Use of hard-coded password. +
  • +Microsoft: +Azure authentication with user credentials. +
  • +
  • +Amazon: +Working with AWS Credentials. +
  • diff --git a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll index 56072496293..928a3562ec6 100644 --- a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll +++ b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll @@ -130,7 +130,8 @@ private predicate javaApiCallablePasswordParam(string s) { s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);3" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, String, String);2" or s = "sun.tools.jconsole.ProxyClient;getCacheKey(String, int, String, String);3" or - s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);1" + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);1" or + s = "com.azure.identity.UsernamePasswordCredentialBuilder;password(String);0" } /** @@ -202,7 +203,8 @@ private predicate javaApiCallableUsernameParam(string s) { s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, String);1" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);2" or s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, int, String);2" or - s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);0" + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);0" or + s = "com.azure.identity.UsernamePasswordCredentialBuilder;username(String);0" } /** @@ -510,5 +512,7 @@ private predicate otherApiCallableCredentialParam(string s) { s = "org.springframework.security.core.userdetails.User;User(String, String, boolean, boolean, boolean, boolean, Collection);0" or s = - "org.springframework.security.core.userdetails.User;User(String, String, boolean, boolean, boolean, boolean, Collection);1" + "org.springframework.security.core.userdetails.User;User(String, String, boolean, boolean, boolean, boolean, Collection);1" or + s = "com.azure.identity.ClientSecretCredentialBuilder;clientSecret(String);0" + } diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAzureCredentials.java b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAzureCredentials.java new file mode 100644 index 00000000000..d243e18d608 --- /dev/null +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedAzureCredentials.java @@ -0,0 +1,66 @@ +import com.azure.identity.ClientSecretCredential; +import com.azure.identity.ClientSecretCredentialBuilder; +import com.azure.identity.UsernamePasswordCredential; +import com.azure.identity.UsernamePasswordCredentialBuilder; +import com.azure.security.keyvault.secrets.SecretClient; +import com.azure.security.keyvault.secrets.SecretClientBuilder; + +public class HardcodedAzureCredentials { + private final String clientId = "81734019-15a3-50t8-3253-5abe78abc3a1"; + private final String username = "username@example.onmicrosoft.com"; + private final String clientSecret = "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_"; + private final String tenantId = "22f367ce-535x-357w-2179-a33517mn166h"; + + //BAD: hard-coded username/password credentials + public void testHardcodedUsernamePassword(String input) { + UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredentialBuilder() + .clientId(clientId) + .username(username) + .password(clientSecret) + .build(); + + SecretClient client = new SecretClientBuilder() + .vaultUrl("https://myKeyVault.vault.azure.net") + .credential(usernamePasswordCredential) + .buildClient(); + } + + //GOOD: username/password credentials stored as environment variables + public void testEnvironmentUsernamePassword(String input) { + UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredentialBuilder() + .clientId(clientId) + .username(System.getenv("myUsername")) + .password(System.getenv("mySuperSecurePass")) + .build(); + + SecretClient client = new SecretClientBuilder() + .vaultUrl("https://myKeyVault.vault.azure.net") + .credential(usernamePasswordCredential) + .buildClient(); + } + + //BAD: hard-coded client secret + public void testHardcodedClientSecret(String input) { + ClientSecretCredential defaultCredential = new ClientSecretCredentialBuilder() + .clientId(clientId) + .clientSecret(clientSecret) + .tenantId(tenantId) + .build(); + } + + //GOOD: client secret stored as environment variables + public void testEnvironmentClientSecret(String input) { + ClientSecretCredential defaultCredential = new ClientSecretCredentialBuilder() + .clientId(clientId) + .clientSecret(System.getenv("myClientSecret")) + .tenantId(tenantId) + .build(); + } + + public static void main(String[] args) { + new HardcodedAzureCredentials().testHardcodedUsernamePassword(args[0]); + new HardcodedAzureCredentials().testEnvironmentUsernamePassword(args[0]); + new HardcodedAzureCredentials().testHardcodedClientSecret(args[0]); + new HardcodedAzureCredentials().testEnvironmentClientSecret(args[0]); + } +} \ No newline at end of file diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected index ccd0259322e..8c87565b553 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsApiCall.expected @@ -10,6 +10,22 @@ edges | FileCredentialTest.java:13:14:13:20 | "admin" : String | FileCredentialTest.java:19:13:19:13 | u : String | | FileCredentialTest.java:19:13:19:13 | u : String | FileCredentialTest.java:22:38:22:45 | v : String | | FileCredentialTest.java:22:38:22:45 | v : String | FileCredentialTest.java:23:36:23:36 | v | +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [clientSecret] : String | HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [clientSecret] : String | HardcodedAzureCredentials.java:63:3:63:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [username] : String | HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [username] : String | +| HardcodedAzureCredentials.java:10:2:10:68 | this <.field> [post update] [username] : String | HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [username] : String | +| HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" : String | HardcodedAzureCredentials.java:10:2:10:68 | this <.field> [post update] [username] : String | +| HardcodedAzureCredentials.java:11:2:11:74 | this <.field> [post update] [clientSecret] : String | HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | HardcodedAzureCredentials.java:11:2:11:74 | this <.field> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [clientSecret] : String | HardcodedAzureCredentials.java:19:13:19:24 | this <.field> [clientSecret] : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [username] : String | HardcodedAzureCredentials.java:18:13:18:20 | this <.field> [username] : String | +| HardcodedAzureCredentials.java:18:13:18:20 | this <.field> [username] : String | HardcodedAzureCredentials.java:18:13:18:20 | username | +| HardcodedAzureCredentials.java:19:13:19:24 | this <.field> [clientSecret] : String | HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | +| HardcodedAzureCredentials.java:43:14:43:38 | parameter this [clientSecret] : String | HardcodedAzureCredentials.java:46:17:46:28 | this <.field> [clientSecret] : String | +| HardcodedAzureCredentials.java:46:17:46:28 | this <.field> [clientSecret] : String | HardcodedAzureCredentials.java:46:17:46:28 | clientSecret | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | HardcodedAzureCredentials.java:15:14:15:42 | parameter this [clientSecret] : String | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [username] : String | HardcodedAzureCredentials.java:15:14:15:42 | parameter this [username] : String | +| HardcodedAzureCredentials.java:63:3:63:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | HardcodedAzureCredentials.java:43:14:43:38 | parameter this [clientSecret] : String | | Test.java:9:16:9:22 | "admin" : String | Test.java:12:13:12:15 | usr : String | | Test.java:9:16:9:22 | "admin" : String | Test.java:15:36:15:38 | usr | | Test.java:9:16:9:22 | "admin" : String | Test.java:17:39:17:41 | usr | @@ -42,6 +58,24 @@ nodes | FileCredentialTest.java:23:36:23:36 | v | semmle.label | v | | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | semmle.label | "ACCESS_KEY" | | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | semmle.label | "SECRET_KEY" | +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [clientSecret] : String | semmle.label | this <.method> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [username] : String | semmle.label | this <.method> [post update] [username] : String | +| HardcodedAzureCredentials.java:10:2:10:68 | this <.field> [post update] [username] : String | semmle.label | this <.field> [post update] [username] : String | +| HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" : String | semmle.label | "username@example.onmicrosoft.com" : String | +| HardcodedAzureCredentials.java:11:2:11:74 | this <.field> [post update] [clientSecret] : String | semmle.label | this <.field> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | semmle.label | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [clientSecret] : String | semmle.label | parameter this [clientSecret] : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [username] : String | semmle.label | parameter this [username] : String | +| HardcodedAzureCredentials.java:18:13:18:20 | this <.field> [username] : String | semmle.label | this <.field> [username] : String | +| HardcodedAzureCredentials.java:18:13:18:20 | username | semmle.label | username | +| HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | semmle.label | clientSecret | +| HardcodedAzureCredentials.java:19:13:19:24 | this <.field> [clientSecret] : String | semmle.label | this <.field> [clientSecret] : String | +| HardcodedAzureCredentials.java:43:14:43:38 | parameter this [clientSecret] : String | semmle.label | parameter this [clientSecret] : String | +| HardcodedAzureCredentials.java:46:17:46:28 | clientSecret | semmle.label | clientSecret | +| HardcodedAzureCredentials.java:46:17:46:28 | this <.field> [clientSecret] : String | semmle.label | this <.field> [clientSecret] : String | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | semmle.label | new HardcodedAzureCredentials(...) [clientSecret] : String | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [username] : String | semmle.label | new HardcodedAzureCredentials(...) [username] : String | +| HardcodedAzureCredentials.java:63:3:63:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | semmle.label | new HardcodedAzureCredentials(...) [clientSecret] : String | | Test.java:9:16:9:22 | "admin" : String | semmle.label | "admin" : String | | Test.java:10:17:10:24 | "123456" : String | semmle.label | "123456" : String | | Test.java:12:13:12:15 | usr : String | semmle.label | usr : String | @@ -72,6 +106,9 @@ nodes | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | FileCredentialTest.java:18:35:18:41 | "admin" | Hard-coded value flows to $@. | FileCredentialTest.java:18:35:18:41 | "admin" | sensitive API call | | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:50:8:61 | "ACCESS_KEY" | sensitive API call | | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | Hard-coded value flows to $@. | HardcodedAWSCredentials.java:8:64:8:75 | "SECRET_KEY" | sensitive API call | +| HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" | HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" : String | HardcodedAzureCredentials.java:18:13:18:20 | username | Hard-coded value flows to $@. | HardcodedAzureCredentials.java:18:13:18:20 | username | sensitive API call | +| HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" | HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | Hard-coded value flows to $@. | HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | sensitive API call | +| HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" | HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | HardcodedAzureCredentials.java:46:17:46:28 | clientSecret | Hard-coded value flows to $@. | HardcodedAzureCredentials.java:46:17:46:28 | clientSecret | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:15:36:15:38 | usr | Hard-coded value flows to $@. | Test.java:15:36:15:38 | usr | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:17:39:17:41 | usr | Hard-coded value flows to $@. | Test.java:17:39:17:41 | usr | sensitive API call | | Test.java:9:16:9:22 | "admin" | Test.java:9:16:9:22 | "admin" : String | Test.java:18:39:18:41 | usr | Hard-coded value flows to $@. | Test.java:18:39:18:41 | usr | sensitive API call | diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected index 05e47dacf3f..cabd4a20ca2 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/HardcodedCredentialsSourceCall.expected @@ -1,11 +1,39 @@ edges +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [clientSecret] : String | HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [username] : String | HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [username] : String | +| HardcodedAzureCredentials.java:10:2:10:68 | this <.field> [post update] [username] : String | HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [username] : String | +| HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" : String | HardcodedAzureCredentials.java:10:2:10:68 | this <.field> [post update] [username] : String | +| HardcodedAzureCredentials.java:11:2:11:74 | this <.field> [post update] [clientSecret] : String | HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | HardcodedAzureCredentials.java:11:2:11:74 | this <.field> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [clientSecret] : String | HardcodedAzureCredentials.java:19:13:19:24 | this <.field> [clientSecret] : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [username] : String | HardcodedAzureCredentials.java:18:13:18:20 | this <.field> [username] : String | +| HardcodedAzureCredentials.java:18:13:18:20 | this <.field> [username] : String | HardcodedAzureCredentials.java:18:13:18:20 | username | +| HardcodedAzureCredentials.java:19:13:19:24 | this <.field> [clientSecret] : String | HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | HardcodedAzureCredentials.java:15:14:15:42 | parameter this [clientSecret] : String | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [username] : String | HardcodedAzureCredentials.java:15:14:15:42 | parameter this [username] : String | | Test.java:10:17:10:24 | "123456" : String | Test.java:26:17:26:20 | pass | | User.java:2:43:2:50 | "123456" : String | User.java:5:15:5:24 | DEFAULT_PW | nodes +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [clientSecret] : String | semmle.label | this <.method> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:8:14:8:38 | this <.method> [post update] [username] : String | semmle.label | this <.method> [post update] [username] : String | +| HardcodedAzureCredentials.java:10:2:10:68 | this <.field> [post update] [username] : String | semmle.label | this <.field> [post update] [username] : String | +| HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" : String | semmle.label | "username@example.onmicrosoft.com" : String | +| HardcodedAzureCredentials.java:11:2:11:74 | this <.field> [post update] [clientSecret] : String | semmle.label | this <.field> [post update] [clientSecret] : String | +| HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | semmle.label | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [clientSecret] : String | semmle.label | parameter this [clientSecret] : String | +| HardcodedAzureCredentials.java:15:14:15:42 | parameter this [username] : String | semmle.label | parameter this [username] : String | +| HardcodedAzureCredentials.java:18:13:18:20 | this <.field> [username] : String | semmle.label | this <.field> [username] : String | +| HardcodedAzureCredentials.java:18:13:18:20 | username | semmle.label | username | +| HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | semmle.label | clientSecret | +| HardcodedAzureCredentials.java:19:13:19:24 | this <.field> [clientSecret] : String | semmle.label | this <.field> [clientSecret] : String | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [clientSecret] : String | semmle.label | new HardcodedAzureCredentials(...) [clientSecret] : String | +| HardcodedAzureCredentials.java:61:3:61:33 | new HardcodedAzureCredentials(...) [username] : String | semmle.label | new HardcodedAzureCredentials(...) [username] : String | | Test.java:10:17:10:24 | "123456" : String | semmle.label | "123456" : String | | Test.java:26:17:26:20 | pass | semmle.label | pass | | User.java:2:43:2:50 | "123456" : String | semmle.label | "123456" : String | | User.java:5:15:5:24 | DEFAULT_PW | semmle.label | DEFAULT_PW | #select +| HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" | HardcodedAzureCredentials.java:10:34:10:67 | "username@example.onmicrosoft.com" : String | HardcodedAzureCredentials.java:18:13:18:20 | username | Hard-coded value flows to $@. | HardcodedAzureCredentials.java:18:13:18:20 | username | sensitive call | +| HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" | HardcodedAzureCredentials.java:11:38:11:73 | "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_" : String | HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | Hard-coded value flows to $@. | HardcodedAzureCredentials.java:19:13:19:24 | clientSecret | sensitive call | | Test.java:10:17:10:24 | "123456" | Test.java:10:17:10:24 | "123456" : String | Test.java:26:17:26:20 | pass | Hard-coded value flows to $@. | Test.java:26:17:26:20 | pass | sensitive call | | User.java:2:43:2:50 | "123456" | User.java:2:43:2:50 | "123456" : String | User.java:5:15:5:24 | DEFAULT_PW | Hard-coded value flows to $@. | User.java:5:15:5:24 | DEFAULT_PW | sensitive call | diff --git a/java/ql/test/query-tests/security/CWE-798/semmle/tests/options b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options index e13da5319f0..4e56d220d7e 100644 --- a/java/ql/test/query-tests/security/CWE-798/semmle/tests/options +++ b/java/ql/test/query-tests/security/CWE-798/semmle/tests/options @@ -1 +1 @@ -// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700 +// semmle-extractor-options: --javac-args -cp ${testdir}/../../../../../stubs/amazon-aws-sdk-1.11.700:${testdir}/../../../../../stubs/azure-sdk-for-java diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/core/credential/TokenCredential.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/core/credential/TokenCredential.java new file mode 100644 index 00000000000..bacaa46a251 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/core/credential/TokenCredential.java @@ -0,0 +1,10 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.core.credential; + +/** + * The interface for credentials that can provide a token. + */ +public interface TokenCredential { +} \ No newline at end of file diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/AadCredentialBuilderBase.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/AadCredentialBuilderBase.java new file mode 100644 index 00000000000..bedaab87e69 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/AadCredentialBuilderBase.java @@ -0,0 +1,43 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +/** + * The base class for credential builders that allow specifying a client ID and tenant ID for an Azure Active Directory. + * @param the type of the credential builder + */ +public abstract class AadCredentialBuilderBase> extends CredentialBuilderBase { + + /** + * Specifies the Azure Active Directory endpoint to acquire tokens. + * @param authorityHost the Azure Active Directory endpoint + * @return An updated instance of this builder with the authority host set as specified. + */ + @SuppressWarnings("unchecked") + public T authorityHost(String authorityHost) { + return null; + } + + /** + * Sets the client ID of the application. + * + * @param clientId the client ID of the application. + * @return An updated instance of this builder with the client id set as specified. + */ + @SuppressWarnings("unchecked") + public T clientId(String clientId) { + return null; + } + + /** + * Sets the tenant ID of the application. + * + * @param tenantId the tenant ID of the application. + * @return An updated instance of this builder with the tenant id set as specified. + */ + @SuppressWarnings("unchecked") + public T tenantId(String tenantId) { + return null; + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredential.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredential.java new file mode 100644 index 00000000000..9b8182451b8 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredential.java @@ -0,0 +1,18 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +import com.azure.core.credential.TokenCredential; + +/** + * An AAD credential that acquires a token with a client secret for an AAD application. + * + *

    Sample: Construct a simple ClientSecretCredential

    + * {@codesnippet com.azure.identity.credential.clientsecretcredential.construct} + * + *

    Sample: Construct a ClientSecretCredential behind a proxy

    + * {@codesnippet com.azure.identity.credential.clientsecretcredential.constructwithproxy} + */ +public class ClientSecretCredential implements TokenCredential { +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredentialBuilder.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredentialBuilder.java new file mode 100644 index 00000000000..85ab73c3060 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/ClientSecretCredentialBuilder.java @@ -0,0 +1,63 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +/** + * Fluent credential builder for instantiating a {@link ClientSecretCredential}. + * + * @see ClientSecretCredential + */ +public class ClientSecretCredentialBuilder extends AadCredentialBuilderBase { + /** + * Sets the client secret for the authentication. + * @param clientSecret the secret value of the AAD application. + * @return An updated instance of this builder. + */ + public ClientSecretCredentialBuilder clientSecret(String clientSecret) { + return null; + } + + /** + * Enables the shared token cache which is disabled by default. If enabled, the credential will store tokens + * in a cache persisted to the machine, protected to the current user, which can be shared by other credentials + * and processes. + * + * @return An updated instance of this builder. + */ + ClientSecretCredentialBuilder enablePersistentCache() { + return null; + } + + /** + * Allows to use an unprotected file specified by cacheFileLocation() instead of + * Gnome keyring on Linux. This is restricted by default. + * + * @return An updated instance of this builder. + */ + ClientSecretCredentialBuilder allowUnencryptedCache() { + return null; + } + + /** + * Configures the persistent shared token cache options and enables the persistent token cache which is disabled + * by default. If configured, the credential will store tokens in a cache persisted to the machine, protected to + * the current user, which can be shared by other credentials and processes. + * + * @param tokenCachePersistenceOptions the token cache configuration options + * @return An updated instance of this builder with the token cache options configured. + */ + public ClientSecretCredentialBuilder tokenCachePersistenceOptions(TokenCachePersistenceOptions + tokenCachePersistenceOptions) { + return null; + } + + /** + * Creates a new {@link ClientCertificateCredential} with the current configurations. + * + * @return a {@link ClientSecretCredentialBuilder} with the current configurations. + */ + public ClientSecretCredential build() { + return null; + } +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/CredentialBuilderBase.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/CredentialBuilderBase.java new file mode 100644 index 00000000000..c1210942ea0 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/CredentialBuilderBase.java @@ -0,0 +1,13 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +/** + * The base class for all the credential builders. + * @param the type of the credential builder + */ +public abstract class CredentialBuilderBase> { + CredentialBuilderBase() { + } +} \ No newline at end of file diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/TokenCachePersistenceOptions.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/TokenCachePersistenceOptions.java new file mode 100644 index 00000000000..d5580fb05f6 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/TokenCachePersistenceOptions.java @@ -0,0 +1,48 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. +package com.azure.identity; + +/** + * Represents the Persistence Token Cache options used to setup the persistent access token cache. + */ +public final class TokenCachePersistenceOptions { + + /** + * Allows to use an unprotected file specified by cacheFileLocation() instead of + * Gnome keyring on Linux. This is restricted by default. For other platforms this setting currently doesn't apply. + * + * @param unencryptedStorageAllowed The flag indicating if unencrypted storage is allowed for the cache or not. + * @return An updated instance of the options bag. + */ + public TokenCachePersistenceOptions setUnencryptedStorageAllowed(boolean unencryptedStorageAllowed) { + return null; + } + + /** + * Gets the status whether unencrypted storage is allowed for the persistent token cache. + * + * @return The status indicating if unencrypted storage is allowed for the persistent token cache. + */ + public boolean isUnencryptedStorageAllowed() { + return false; + } + + /** + * Set the name uniquely identifying the cache. + * + * @param name the name of the cache + * @return the updated instance of the cache. + */ + public TokenCachePersistenceOptions setName(String name) { + return null; + } + + /** + * Get the name uniquely identifying the cache. + * + * @return the name of the cache. + */ + public String getName() { + return null; + } +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredential.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredential.java new file mode 100644 index 00000000000..5cb9463eb95 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredential.java @@ -0,0 +1,14 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +import com.azure.core.credential.TokenCredential; + +/** + * An AAD credential that acquires a token with a username and a password. Users with 2FA/MFA (Multi-factored auth) + * turned on will not be able to use this credential. Please use {@link DeviceCodeCredential} or {@link + * InteractiveBrowserCredential} instead, or create a service principal if you want to authenticate silently. + */ +public class UsernamePasswordCredential implements TokenCredential { +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredentialBuilder.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredentialBuilder.java new file mode 100644 index 00000000000..b6aa411ed84 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/identity/UsernamePasswordCredentialBuilder.java @@ -0,0 +1,74 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.identity; + +import com.azure.security.keyvault.secrets.SecretClient; + +/** + * Fluent credential builder for instantiating a {@link UsernamePasswordCredential}. + * + * @see UsernamePasswordCredential + */ +public class UsernamePasswordCredentialBuilder extends AadCredentialBuilderBase { + /** + * Sets the username of the user. + * @param username the username of the user + * @return the UserCredentialBuilder itself + */ + public UsernamePasswordCredentialBuilder username(String username) { + return null; + } + + /** + * Sets the password of the user. + * @param password the password of the user + * @return the UserCredentialBuilder itself + */ + public UsernamePasswordCredentialBuilder password(String password) { + return null; + } + + /** + * Configures the persistent shared token cache options and enables the persistent token cache which is disabled + * by default. If configured, the credential will store tokens in a cache persisted to the machine, protected to + * the current user, which can be shared by other credentials and processes. + * + * @param tokenCachePersistenceOptions the token cache configuration options + * @return An updated instance of this builder with the token cache options configured. + */ + public UsernamePasswordCredentialBuilder tokenCachePersistenceOptions(TokenCachePersistenceOptions + tokenCachePersistenceOptions) { + return null; + } + + /** + * Allows to use an unprotected file specified by cacheFileLocation() instead of + * Gnome keyring on Linux. This is restricted by default. + * + * @return An updated instance of this builder. + */ + UsernamePasswordCredentialBuilder allowUnencryptedCache() { + return null; + } + + /** + * Enables the shared token cache which is disabled by default. If enabled, the credential will store tokens + * in a cache persisted to the machine, protected to the current user, which can be shared by other credentials + * and processes. + * + * @return An updated instance of this builder with if the shared token cache enabled specified. + */ + UsernamePasswordCredentialBuilder enablePersistentCache() { + return null; + } + + /** + * Creates a new {@link UsernamePasswordCredential} with the current configurations. + * + * @return a {@link UsernamePasswordCredential} with the current configurations. + */ + public UsernamePasswordCredential build() { + return null; + } +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClient.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClient.java new file mode 100644 index 00000000000..94cdc7d1be7 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClient.java @@ -0,0 +1,155 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.security.keyvault.secrets; + +import com.azure.security.keyvault.secrets.models.KeyVaultSecret; +import com.azure.security.keyvault.secrets.models.SecretProperties; + +/** + * The SecretClient provides synchronous methods to manage {@link KeyVaultSecret secrets} in the Azure Key Vault. The client + * supports creating, retrieving, updating, deleting, purging, backing up, restoring, and listing the {@link KeyVaultSecret + * secrets}. The client also supports listing {@link DeletedSecret deleted secrets} for a soft-delete enabled Azure Key + * Vault. + * + *

    Construct the sync client

    + * {@codesnippet com.azure.security.keyvault.secretclient.sync.construct} + * + * @see SecretClientBuilder + * @see PagedIterable + */ +public final class SecretClient { + + /** + * Gets the vault endpoint url to which service requests are sent to. + * @return the vault endpoint url. + */ + public String getVaultUrl() { + return null; + } + + /** + * Adds a secret to the key vault if it does not exist. If the named secret exists, a new version of the secret is + * created. This operation requires the {@code secrets/set} permission. + * + *

    The {@link SecretProperties#getExpiresOn() expires}, {@link SecretProperties#getContentType() contentType}, + * and {@link SecretProperties#getNotBefore() notBefore} values in {@code secret} are optional. + * If not specified, {@link SecretProperties#isEnabled() enabled} is set to true by key vault.

    + * + *

    Code sample

    + *

    Creates a new secret in the key vault. Prints out the details of the newly created secret returned in the + * response.

    + * {@codesnippet com.azure.security.keyvault.secretclient.setSecret#secret} + * + * @param secret The Secret object containing information about the secret and its properties. The properties + * {@link KeyVaultSecret#getName() secret.name} and {@link KeyVaultSecret#getValue() secret.value} cannot be + * null. + * @return The {@link KeyVaultSecret created secret}. + * @throws NullPointerException if {@code secret} is {@code null}. + * @throws ResourceModifiedException if {@code secret} is malformed. + * @throws HttpResponseException if {@link KeyVaultSecret#getName() name} or {@link KeyVaultSecret#getValue() value} + * is an empty string. + */ + public KeyVaultSecret setSecret(KeyVaultSecret secret) { + return null; + } + + /** + * Adds a secret to the key vault if it does not exist. If the named secret exists, a new version of the secret is + * created. This operation requires the {@code secrets/set} permission. + * + *

    Code sample

    + *

    Creates a new secret in the key vault. Prints out the details of the newly created secret returned in the + * response.

    + * {@codesnippet com.azure.security.keyvault.secretclient.setSecret#string-string} + * + * @param name The name of the secret. It is required and cannot be null. + * @param value The value of the secret. It is required and cannot be null. + * @return The {@link KeyVaultSecret created secret}. + * @throws ResourceModifiedException if invalid {@code name} or {@code value} is specified. + * @throws HttpResponseException if {@code name} or {@code value} is empty string. + */ + public KeyVaultSecret setSecret(String name, String value) { + return null; + } + + /** + * Gets the specified secret with specified version from the key vault. This operation requires the + * {@code secrets/get} permission. + * + *

    Code sample

    + *

    Gets a specific version of the secret in the key vault. Prints out the details of the returned secret.

    + * {@codesnippet com.azure.security.keyvault.secretclient.getSecret#string-string} + * + * @param name The name of the secret, cannot be null. + * @param version The version of the secret to retrieve. If this is an empty string or null, this call is + * equivalent to calling {@link #getSecret(String)}, with the latest version being retrieved. + * @return The requested {@link KeyVaultSecret secret}. + * @throws ResourceNotFoundException when a secret with {@code name} and {@code version} doesn't exist in the + * key vault. + * @throws HttpResponseException if {@code name} or {@code version} is empty string. + */ + public KeyVaultSecret getSecret(String name, String version) { + return null; + } + + /** + * Gets the latest version of the specified secret from the key vault. + * This operation requires the {@code secrets/get} permission. + * + *

    Code sample

    + *

    Gets the latest version of the secret in the key vault. Prints out the details of the returned secret.

    + * {@codesnippet com.azure.security.keyvault.secretclient.getSecret#string} + * + * @param name The name of the secret. + * @return The requested {@link KeyVaultSecret}. + * @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault. + * @throws HttpResponseException if {@code name} is empty string. + */ + public KeyVaultSecret getSecret(String name) { + return null; + } + + /** + * Updates the attributes associated with the secret. The value of the secret in the key vault cannot be changed. + * Only attributes populated in {@code secretProperties} are changed. Attributes not specified in the request are + * not changed. This operation requires the {@code secrets/set} permission. + * + *

    The {@code secret} is required and its fields {@link SecretProperties#getName() name} and + * {@link SecretProperties#getVersion() version} cannot be null.

    + * + *

    Code sample

    + *

    Gets the latest version of the secret, changes its expiry time, and the updates the secret in the key + * vault.

    + * {@codesnippet com.azure.security.keyvault.secretclient.updateSecretProperties#secretProperties} + * + * @param secretProperties The {@link SecretProperties secret properties} object with updated properties. + * @return The {@link SecretProperties updated secret}. + * @throws NullPointerException if {@code secret} is {@code null}. + * @throws ResourceNotFoundException when a secret with {@link SecretProperties#getName() name} and {@link + * SecretProperties#getVersion() version} doesn't exist in the key vault. + * @throws HttpResponseException if {@link SecretProperties#getName() name} or {@link SecretProperties#getVersion() version} is + * empty string. + */ + public SecretProperties updateSecretProperties(SecretProperties secretProperties) { + return null; + } + + /** + * Requests a backup of the secret be downloaded to the client. All versions of the secret will be downloaded. + * This operation requires the {@code secrets/backup} permission. + * + *

    Code sample

    + *

    Backs up the secret from the key vault and prints out the length of the secret's backup byte array returned in + * the response

    + * {@codesnippet com.azure.security.keyvault.secretclient.backupSecret#string} + * + * @param name The name of the secret. + * @return A {@link Response} whose {@link Response#getValue() value} contains the backed up secret blob. + * @throws ResourceNotFoundException when a secret with {@code name} doesn't exist in the key vault. + * @throws HttpResponseException when a secret with {@code name} is empty string. + */ + public byte[] backupSecret(String name) { + return null; + } +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClientBuilder.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClientBuilder.java new file mode 100644 index 00000000000..0a90f44f8dd --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/SecretClientBuilder.java @@ -0,0 +1,92 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.security.keyvault.secrets; + +import com.azure.core.credential.TokenCredential; + +/** + * This class provides a fluent builder API to help aid the configuration and instantiation of the {@link + * SecretAsyncClient secret async client} and {@link SecretClient secret client}, + * by calling {@link SecretClientBuilder#buildAsyncClient() buildAsyncClient} and {@link + * SecretClientBuilder#buildClient() buildClient} respectively. + * It constructs an instance of the desired client. + * + *

    The minimal configuration options required by {@link SecretClientBuilder secretClientBuilder} to build + * {@link SecretAsyncClient} are {@link String vaultUrl} and {@link TokenCredential credential}.

    + * + * {@codesnippet com.azure.security.keyvault.secrets.async.secretclient.construct} + * + *

    Samples to construct the sync client

    + * {@codesnippet com.azure.security.keyvault.secretclient.sync.construct} + * + *

    The {@link HttpLogDetailLevel log detail level}, multiple custom {@link HttpLoggingPolicy policies} and custom + * {@link HttpClient http client} can be optionally configured in the {@link SecretClientBuilder}.

    + * + * {@codesnippet com.azure.security.keyvault.secrets.async.secretclient.withhttpclient.instantiation} + * + *

    Alternatively, custom {@link HttpPipeline http pipeline} with custom {@link HttpPipelinePolicy} policies and + * {@link String vaultUrl} + * can be specified. It provides finer control over the construction of {@link SecretAsyncClient client}

    + * + * {@codesnippet com.azure.security.keyvault.secrets.async.secretclient.pipeline.instantiation} + * + * @see SecretClient + * @see SecretAsyncClient + */ +public final class SecretClientBuilder { + /** + * The constructor with defaults. + */ + public SecretClientBuilder() { + } + + /** + * Creates a {@link SecretClient} based on options set in the builder. + * Every time {@code buildClient()} is called, a new instance of {@link SecretClient} is created. + * + *

    If {@link SecretClientBuilder#pipeline(HttpPipeline) pipeline} is set, then the {@code pipeline} and + * {@link SecretClientBuilder#vaultUrl(String) serviceEndpoint} are used to create the + * {@link SecretClientBuilder client}. All other builder settings are ignored. If {@code pipeline} is not set, + * then {@link SecretClientBuilder#credential(TokenCredential) key vault credential}, and + * {@link SecretClientBuilder#vaultUrl(String)} key vault url are required to build the {@link SecretClient + * client}.

    + * + * @return A {@link SecretClient} with the options set from the builder. + * + * @throws IllegalStateException If {@link SecretClientBuilder#credential(TokenCredential)} or + * {@link SecretClientBuilder#vaultUrl(String)} have not been set. + */ + public SecretClient buildClient() { + return null; + } + + /** + * Sets the vault URL to send HTTP requests to. + * + * @param vaultUrl The vault url is used as destination on Azure to send requests to. If you have a secret + * identifier, create a new {@link KeyVaultSecretIdentifier} to parse it and obtain the {@code vaultUrl} and + * other information. + * + * @return The updated {@link SecretClientBuilder} object. + * + * @throws IllegalArgumentException If {@code vaultUrl} is null or it cannot be parsed into a valid URL. + * @throws NullPointerException If {@code vaultUrl} is {@code null}. + */ + public SecretClientBuilder vaultUrl(String vaultUrl) { + return null; + } + + /** + * Sets the credential to use when authenticating HTTP requests. + * + * @param credential The credential to use for authenticating HTTP requests. + * + * @return The updated {@link SecretClientBuilder} object. + * + * @throws NullPointerException If {@code credential} is {@code null}. + */ + public SecretClientBuilder credential(TokenCredential credential) { + return null; + } +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/KeyVaultSecret.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/KeyVaultSecret.java new file mode 100644 index 00000000000..1f2f252a323 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/KeyVaultSecret.java @@ -0,0 +1,78 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.security.keyvault.secrets.models; + +import com.azure.security.keyvault.secrets.SecretClient; + +import java.util.Map; +import java.util.Objects; + +/** + * Secret is the resource consisting of name, value and its attributes specified in {@link SecretProperties}. + * It is managed by Secret Service. + * + * @see SecretClient + * @see SecretAsyncClient + */ +public class KeyVaultSecret { + /** + * Creates an empty instance of the Secret. + */ + KeyVaultSecret() { + } + + /** + * Creates a Secret with {@code name} and {@code value}. + * + * @param name The name of the secret. + * @param value the value of the secret. + */ + public KeyVaultSecret(String name, String value) { + } + + /** + * Get the value of the secret. + * + * @return the secret value + */ + public String getValue() { + return null; + } + + /** + * Get the secret identifier. + * + * @return the secret identifier. + */ + public String getId() { + return null; + } + + /** + * Get the secret name. + * + * @return the secret name. + */ + public String getName() { + return null; + } + + /** + * Get the secret properties + * @return the Secret properties + */ + public SecretProperties getProperties() { + return null; + } + + /** + * Set the secret properties + * @param properties The Secret properties + * @throws NullPointerException if {@code properties} is null. + * @return the updated secret object + */ + public KeyVaultSecret setProperties(SecretProperties properties) { + return null; + } +} diff --git a/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/SecretProperties.java b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/SecretProperties.java new file mode 100644 index 00000000000..750db3ff177 --- /dev/null +++ b/java/ql/test/stubs/azure-sdk-for-java/com/azure/security/keyvault/secrets/models/SecretProperties.java @@ -0,0 +1,145 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +package com.azure.security.keyvault.secrets.models; + +import java.util.Map; + +import com.azure.security.keyvault.secrets.SecretClient; + +/** + * SecretProperties is the resource containing all the properties of the secret except its value. + * It is managed by the Secret Service. + * + * @see SecretClient + * @see SecretAsyncClient + */ +public class SecretProperties { + SecretProperties(String secretName) { + } + + /** + * Creates empty instance of SecretProperties. + */ + public SecretProperties() { } + + /** + * Get the secret name. + * + * @return the name of the secret. + */ + public String getName() { + return null; + } + + /** + * Get the recovery level of the secret. + + * @return the recoveryLevel of the secret. + */ + public String getRecoveryLevel() { + return null; + } + + /** + * Get the enabled value. + * + * @return the enabled value + */ + public Boolean isEnabled() { + return false; + } + + /** + * Set the enabled value. + * + * @param enabled The enabled value to set + * @throws NullPointerException if {@code enabled} is null. + * @return the SecretProperties object itself. + */ + public SecretProperties setEnabled(Boolean enabled) { + return null; + } + + /** + * Get the secret identifier. + * + * @return the secret identifier. + */ + public String getId() { + return null; + } + + /** + * Get the content type. + * + * @return the content type. + */ + public String getContentType() { + return null; + } + + /** + * Set the contentType. + * + * @param contentType The contentType to set + * @return the updated SecretProperties object itself. + */ + public SecretProperties setContentType(String contentType) { + return null; + } + + /** + * Get the tags associated with the secret. + * + * @return the value of the tags. + */ + public Map getTags() { + return null; + } + + /** + * Set the tags to be associated with the secret. + * + * @param tags The tags to set + * @return the updated SecretProperties object itself. + */ + public SecretProperties setTags(Map tags) { + return null; + } + + /** + * Get the keyId identifier. + * + * @return the keyId identifier. + */ + public String getKeyId() { + return null; + } + + /** + * Get the managed value. + * + * @return the managed value + */ + public Boolean isManaged() { + return null; + } + + /** + * Get the version of the secret. + * + * @return the version of the secret. + */ + public String getVersion() { + return null; + } + + /** + * Gets the number of days a secret is retained before being deleted for a soft delete-enabled Key Vault. + * @return the recoverable days. + */ + public Integer getRecoverableDays() { + return null; + } +} From 4d014717b6a109d61ae3f9c803092f8df27ede07 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Wed, 12 May 2021 15:50:40 +0000 Subject: [PATCH 2/5] Add a change note and reset the qhelp file --- ...hardcoded-azure-credentials-in-api-call.md | 3 ++ .../CWE-798/HardcodedCredentialsApiCall.qhelp | 30 ------------------- 2 files changed, 3 insertions(+), 30 deletions(-) create mode 100644 java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md diff --git a/java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md b/java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md new file mode 100644 index 00000000000..48cbc7c4760 --- /dev/null +++ b/java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md @@ -0,0 +1,3 @@ +lgtm,codescanning +* The query "Hard-coded credential in API call" (`java/hardcoded-credential-api-call`) + now recognizes hard-coded authentication credentials with Azure SDK for Java. diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp index efcf6b15abf..231140a287e 100644 --- a/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp +++ b/java/ql/src/Security/CWE/CWE-798/HardcodedCredentialsApiCall.qhelp @@ -32,28 +32,6 @@ Instead, the user name and password could be supplied through environment variables, which can be set externally without hard-coding credentials in the source code.

    - -

    - The following code example connects to AWS using a hard-coded access key ID and secret key: -

    - - - -

    - Instead, the access key ID and secret key could be supplied through environment variables, - which can be set externally without hard-coding credentials in the source code. -

    - -

    - The following code example connects to Azure using a hard-coded user name and password or client secret: -

    - - - -

    - Instead, the username and password or client secret could be supplied through environment variables, - which can be set externally without hard-coding credentials in the source code. -

    @@ -61,14 +39,6 @@ OWASP: Use of hard-coded password. -
  • -Microsoft: -Azure authentication with user credentials. -
  • -
  • -Amazon: -Working with AWS Credentials. -
  • From 9ef58e378c14ec721d320f9e0e678207ce456d49 Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 14 May 2021 11:01:25 +0000 Subject: [PATCH 3/5] Remove the sample Java file in the src folder --- .../CWE-798/HardcodedAzureCredentials.java | 52 ------------------- 1 file changed, 52 deletions(-) delete mode 100644 java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java diff --git a/java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java b/java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java deleted file mode 100644 index a8b52aa43a1..00000000000 --- a/java/ql/src/Security/CWE/CWE-798/HardcodedAzureCredentials.java +++ /dev/null @@ -1,52 +0,0 @@ -public class HardcodedAzureCredentials { - private final String clientId = "81734019-15a3-50t8-3253-5abe78abc3a1"; - private final String username = "username@example.onmicrosoft.com"; - private final String clientSecret = "1n1.qAc~3Q-1t38aF79Xzv5AUEfR5-ct3_"; - private final String tenantId = "22f367ce-535x-357w-2179-a33517mn166h"; - - //BAD: hard-coded username/password credentials - public void testHardcodedUsernamePassword(String input) { - UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredentialBuilder() - .clientId(clientId) - .username(username) - .password(clientSecret) - .build(); - - SecretClient client = new SecretClientBuilder() - .vaultUrl("https://myKeyVault.vault.azure.net") - .credential(usernamePasswordCredential) - .buildClient(); - } - - //GOOD: username/password credentials stored as environment variables - public void testEnvironmentUsernamePassword(String input) { - UsernamePasswordCredential usernamePasswordCredential = new UsernamePasswordCredentialBuilder() - .clientId(clientId) - .username(System.getenv("myUsername")) - .password(System.getenv("mySuperSecurePass")) - .build(); - - SecretClient client = new SecretClientBuilder() - .vaultUrl("https://myKeyVault.vault.azure.net") - .credential(usernamePasswordCredential) - .buildClient(); - } - - //BAD: hard-coded client secret - public void testHardcodedClientSecret(String input) { - ClientSecretCredential defaultCredential = new ClientSecretCredentialBuilder() - .clientId(clientId) - .clientSecret(clientSecret) - .tenantId(tenantId) - .build(); - } - - //GOOD: client secret stored as environment variables - public void testEnvironmentClientSecret(String input) { - ClientSecretCredential defaultCredential = new ClientSecretCredentialBuilder() - .clientId(clientId) - .clientSecret(System.getenv("myClientSecret")) - .tenantId(tenantId) - .build(); - } -} \ No newline at end of file From 1a072f3bb96281bd10f467697775836236fd3a5f Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Fri, 14 May 2021 20:38:23 +0000 Subject: [PATCH 4/5] Move APIs from predicates flagged auto-generated to the other section --- java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll index 928a3562ec6..afbefb7b878 100644 --- a/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll +++ b/java/ql/src/Security/CWE/CWE-798/SensitiveApi.qll @@ -129,9 +129,7 @@ private predicate javaApiCallablePasswordParam(string s) { s = "sun.tools.jconsole.ProxyClient;ProxyClient(String, int, String, String);3" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);3" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, String, String);2" or - s = "sun.tools.jconsole.ProxyClient;getCacheKey(String, int, String, String);3" or - s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);1" or - s = "com.azure.identity.UsernamePasswordCredentialBuilder;password(String);0" + s = "sun.tools.jconsole.ProxyClient;getCacheKey(String, int, String, String);3" } /** @@ -202,9 +200,7 @@ private predicate javaApiCallableUsernameParam(string s) { s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, String, String);1" or s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, String);1" or s = "sun.tools.jconsole.ProxyClient;getProxyClient(String, int, String, String);2" or - s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, int, String);2" or - s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);0" or - s = "com.azure.identity.UsernamePasswordCredentialBuilder;username(String);0" + s = "sun.tools.jconsole.ProxyClient;getConnectionName(String, int, String);2" } /** @@ -513,6 +509,9 @@ private predicate otherApiCallableCredentialParam(string s) { "org.springframework.security.core.userdetails.User;User(String, String, boolean, boolean, boolean, boolean, Collection);0" or s = "org.springframework.security.core.userdetails.User;User(String, String, boolean, boolean, boolean, boolean, Collection);1" or + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);0" or + s = "com.amazonaws.auth.BasicAWSCredentials;BasicAWSCredentials(String, String);1" or + s = "com.azure.identity.UsernamePasswordCredentialBuilder;username(String);0" or + s = "com.azure.identity.UsernamePasswordCredentialBuilder;password(String);0" or s = "com.azure.identity.ClientSecretCredentialBuilder;clientSecret(String);0" - } From 7af198434863fac4364bb9ad5e44896239ec44ad Mon Sep 17 00:00:00 2001 From: luchua-bc Date: Mon, 17 May 2021 11:35:35 +0000 Subject: [PATCH 5/5] Update the change note --- .../2021-05-12-hardcoded-azure-credentials-in-api-call.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md b/java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md index 48cbc7c4760..a5b55ba1b6d 100644 --- a/java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md +++ b/java/change-notes/2021-05-12-hardcoded-azure-credentials-in-api-call.md @@ -1,3 +1,3 @@ lgtm,codescanning * The query "Hard-coded credential in API call" (`java/hardcoded-credential-api-call`) - now recognizes hard-coded authentication credentials with Azure SDK for Java. + now recognizes hard-coded authentication credentials passed to the Azure SDK for Java.