Skip to content

Commit

Permalink
Add ClientCertificateCredential (#3578)
Browse files Browse the repository at this point in the history
* Add ClientCertificateCredential

* Update unit test

* cspell

* Update Readme

* Cosmetic fixes

* Changelog to mention env cred update

* Fix warning

* cspell

* Tell CI to install openssl

* openssl for all Windows

* update dependency manifest

* Re-phrase changelog

* Clang warnings

* Clang warning

* Clang warning - 2

* Ubuntu18 warning

* Update sdk/identity/azure-identity/CHANGELOG.md

Co-authored-by: Victor Vazquez <[email protected]>

* PR feedback

Co-authored-by: Anton Kolesnyk <[email protected]>
Co-authored-by: Victor Vazquez <[email protected]>
  • Loading branch information
3 people authored Apr 28, 2022
1 parent d1be7c8 commit 5cb6086
Show file tree
Hide file tree
Showing 17 changed files with 793 additions and 15 deletions.
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",
"CMAKE_SYSTEM_NAME": "WindowsStore",
"CMAKE_SYSTEM_VERSION": "10.0",
"BuildArgs": "--parallel 8 --config Release"
Expand Down
2 changes: 2 additions & 0 deletions sdk/identity/azure-identity/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### Features Added

- Added `ClientCertificateCredential`, and updated `EnvironmentCredential` to support client certificate authentication.

### Breaking Changes

### Bugs Fixed
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:

#### 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.

## 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);

/**
* @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

0 comments on commit 5cb6086

Please sign in to comment.