Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ClientCertificateCredential #3578

Merged
merged 18 commits into from
Apr 28, 2022
Merged
5 changes: 2 additions & 3 deletions eng/pipelines/templates/stages/platform-matrix.json
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@
{
"StaticConfigs": {
"Windows2019": {
"VcpkgInstall": "openssl",
"OSVmImage": "MMS2019",
"Pool": "azsdk-pool-mms-win-2019-general",
"CMAKE_GENERATOR": "Visual Studio 16 2019",
Expand All @@ -77,13 +78,11 @@
},
"TargetPlatform": {
"UWP_debug": {
"VcpkgInstall": "openssl",
"CMAKE_SYSTEM_NAME": "WindowsStore",
"CMAKE_SYSTEM_NAME": "WindowsStore",
"CMAKE_SYSTEM_VERSION": "10.0",
"BuildArgs": "--parallel 8 --config Debug"
},
"UWP_release": {
"VcpkgInstall": "openssl",
antkmsft marked this conversation as resolved.
Show resolved Hide resolved
"CMAKE_SYSTEM_NAME": "WindowsStore",
"CMAKE_SYSTEM_VERSION": "10.0",
"BuildArgs": "--parallel 8 --config Release"
Expand Down
1 change: 1 addition & 0 deletions sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
## 1.3.0-beta.2 (Unreleased)

### Features Added
- Added `ClientCertificateCredential`, and updated `EnvironmentCredential` to support client certificate authentication.
antkmsft marked this conversation as resolved.
Show resolved Hide resolved

### Breaking Changes

Expand Down
5 changes: 5 additions & 0 deletions sdk/identity/azure-identity/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ endif()
set(
AZURE_IDENTITY_HEADER
inc/azure/identity/chained_token_credential.hpp
inc/azure/identity/client_certificate_credential.hpp
inc/azure/identity/client_secret_credential.hpp
inc/azure/identity/dll_import_export.hpp
inc/azure/identity/environment_credential.hpp
Expand All @@ -60,6 +61,7 @@ set(
src/private/package_version.hpp
src/private/token_credential_impl.hpp
src/chained_token_credential.cpp
src/client_certificate_credential.cpp
src/client_secret_credential.cpp
src/environment_credential.cpp
src/managed_identity_credential.cpp
Expand All @@ -85,6 +87,9 @@ target_include_directories(

target_link_libraries(azure-identity PUBLIC Azure::azure-core)

find_package(OpenSSL REQUIRED)
target_link_libraries(azure-identity PRIVATE OpenSSL::Crypto)

get_az_version("${CMAKE_CURRENT_SOURCE_DIR}/src/private/package_version.hpp")
generate_documentation(azure-identity ${AZ_LIBRARY_VERSION})

Expand Down
33 changes: 32 additions & 1 deletion sdk/identity/azure-identity/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -45,11 +45,16 @@ The Azure Identity library focuses on OAuth authentication with Azure Active dir
<td>authenticates a service principal using a secret</td>
<td><a href="https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals">Service principal authentication</a></td>
</tr>
<tr>
<td><code>ClientCertificateCredential</code></td>
<td>authenticates a service principal using a certificate</td>
<td><a href="https://docs.microsoft.com/azure/active-directory/develop/app-objects-and-service-principals">Service principal authentication</a></td>
</tr>
</tbody>
</table>

## Environment Variables
`EnvironmentCredential` can be configured with environment variables.
`EnvironmentCredential` can be configured with environment variables. Each type of authentication requires values for specific variables:s

#### Service principal with secret
<table border="1" width="100%">
Expand All @@ -75,6 +80,32 @@ The Azure Identity library focuses on OAuth authentication with Azure Active dir
</tbody>
</table>

#### Service principal with certificate
<table border="1" width="100%">
<thead>
<tr>
<th>variable name</th>
<th>value</th>
</tr>
</thead>
<tbody>
<tr>
<td><code>AZURE_CLIENT_ID</code></td>
<td>id of an Azure Active Directory application</td>
</tr>
<tr>
<td><code>AZURE_TENANT_ID</code></td>
<td>id of the application's Azure Active Directory tenant</td>
</tr>
<tr>
<td><code>AZURE_CLIENT_CERTIFICATE_PATH</code></td>
<td>path to a PEM-encoded certificate file including private key (without password protection)</td>
</tr>
</tbody>
</table>

Configuration is attempted in the above order. For example, if values for a client secret and certificate are both present, the client secret will be used.
antkmsft marked this conversation as resolved.
Show resolved Hide resolved

## Managed Identity Support
The [Managed identity authentication](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/overview) is supported via the `ManagedIdentityCredential` for the following Azure Services:
* [Azure Virtual Machines](https://docs.microsoft.com/azure/active-directory/managed-identities-azure-resources/how-to-use-vm-token)
Expand Down
1 change: 1 addition & 0 deletions sdk/identity/azure-identity/inc/azure/identity.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#pragma once

#include "azure/identity/chained_token_credential.hpp"
#include "azure/identity/client_certificate_credential.hpp"
#include "azure/identity/client_secret_credential.hpp"
#include "azure/identity/dll_import_export.hpp"
#include "azure/identity/environment_credential.hpp"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT

/**
* @file
* @brief Client Certificate Credential and options.
*/

#pragma once

#include "azure/identity/dll_import_export.hpp"

#include <azure/core/credentials/credentials.hpp>
#include <azure/core/credentials/token_credential_options.hpp>
#include <azure/core/url.hpp>

#include <memory>
#include <string>

namespace Azure { namespace Identity {
namespace _detail {
class TokenCredentialImpl;
} // namespace _detail

/**
* @brief Options for client certificate authentication.
*
*/
struct ClientCertificateCredentialOptions final : public Core::Credentials::TokenCredentialOptions
{
};

/**
* @brief Client Certificate Credential authenticates with the Azure services using a Tenant ID,
* Client ID and a client certificate.
*
*/
class ClientCertificateCredential final : public Core::Credentials::TokenCredential {
private:
std::unique_ptr<_detail::TokenCredentialImpl> m_tokenCredentialImpl;
Core::Url m_requestUrl;
std::string m_requestBody;
std::string m_tokenHeaderEncoded;
std::string m_tokenPayloadStaticPart;
void* m_pkey;

public:
/**
* @brief Constructs a Client Secret Credential.
*
* @param tenantId Tenant ID.
* @param clientId Client ID.
* @param clientCertificatePath Client certificate path.
* @param options Options for token retrieval.
*/
explicit ClientCertificateCredential(
std::string const& tenantId,
std::string const& clientId,
std::string const& clientCertificatePath,
Core::Credentials::TokenCredentialOptions const& options
= Core::Credentials::TokenCredentialOptions());

/**
* @brief Constructs a Client Secret Credential.
*
* @param tenantId Tenant ID.
* @param clientId Client ID.
* @param clientCertificatePath Client certificate path.
* @param options Options for token retrieval.
*/
explicit ClientCertificateCredential(
std::string const& tenantId,
std::string const& clientId,
std::string const& clientCertificatePath,
ClientCertificateCredentialOptions const& options);
antkmsft marked this conversation as resolved.
Show resolved Hide resolved

/**
* @brief Destructs `%ClientCertificateCredential`.
*
*/
~ClientCertificateCredential() override;

/**
* @brief Gets an authentication token.
*
* @param tokenRequestContext A context to get the token in.
* @param context A context to control the request lifetime.
*
* @throw Azure::Core::Credentials::AuthenticationException Authentication error occurred.
*/
Core::Credentials::AccessToken GetToken(
Core::Credentials::TokenRequestContext const& tokenRequestContext,
Core::Context const& context) const override;
};

}} // namespace Azure::Identity
5 changes: 5 additions & 0 deletions sdk/identity/azure-identity/samples/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ target_link_libraries(chained_token_credential_sample PRIVATE azure-identity)
target_include_directories(chained_token_credential_sample PRIVATE .)
create_per_service_target_build_for_sample(identity chained_token_credential_sample)

add_executable(client_certificate_credential_sample client_certificate_credential.cpp)
target_link_libraries(client_certificate_credential_sample PRIVATE azure-identity)
target_include_directories(client_certificate_credential_sample PRIVATE .)
create_per_service_target_build_for_sample(identity client_certificate_credential_sample)

add_executable(client_secret_credential_sample client_secret_credential.cpp)
target_link_libraries(client_secret_credential_sample PRIVATE azure-identity)
target_include_directories(client_secret_credential_sample PRIVATE .)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// SPDX-License-Identifier: MIT

#include <iostream>

#include <azure/identity/client_certificate_credential.hpp>

#include <azure/service/client.hpp>

// These functions should be getting the real Tenant ID, Client ID, and the Client Certificate to
// authenticate.
std::string GetTenantId() { return std::string(); }
std::string GetClientId() { return std::string(); }
std::string GetClientCertificatePath() { return std::string(); }

int main()
{
try
{
// Step 1: Initialize Client Certificate Credential.
auto clientCertificateCredential
= std::make_shared<Azure::Identity::ClientCertificateCredential>(
GetTenantId(), GetClientId(), GetClientCertificatePath());

// Step 2: Pass the credential to an Azure Service Client.
Azure::Service::Client azureServiceClient("serviceUrl", clientCertificateCredential);

// Step 3: Start using the Azure Service Client.
azureServiceClient.DoSomething(Azure::Core::Context::ApplicationContext);

std::cout << "Success!" << std::endl;
}
catch (const Azure::Core::Credentials::AuthenticationException& exception)
{
// Step 4: Handle authentication errors, if needed
// (invalid credential parameters, insufficient permissions).
std::cout << "Authentication error: " << exception.what() << std::endl;
return 1;
}

return 0;
}
Loading