Skip to content

Commit 8683553

Browse files
committed
updates
1 parent 8ab31e9 commit 8683553

File tree

4 files changed

+60
-62
lines changed

4 files changed

+60
-62
lines changed

articles/app-service/app-service-web-configure-tls-mutual-auth.md

Lines changed: 55 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,34 @@ You can restrict access to your Azure App Service app by enabling various types
2626

2727
## Enable client certificates
2828

29-
When you enable client certificates for your app, you should select your choice of client certificate mode. Each mode defines how your app handles incoming client certificates.
29+
When you enable client certificates for your app, you should select your choice of client certificate mode. The mode defines how your app handles incoming client certificates. The modes are described in the following table:
3030

3131
|Client certificate mode|Description|
3232
|-|-|
3333
|Required|All requests require a client certificate.|
34-
|Optional|Requests can use a client certificate and clients are prompted for a certificate by default. For example, browser clients show a prompt to select a certificate for authentication.|
35-
|Optional Interactive User|Requests can use a client certificate and clients aren't prompted for a certificate by default. For example, browser clients don't show a prompt to select a certificate for authentication.|
34+
|Optional|Requests can use a client certificate. Clients are prompted for a certificate by default. For example, browser clients show a prompt to select a certificate for authentication.|
35+
|Optional Interactive User|Requests can use a client certificate. Clients aren't prompted for a certificate by default. For example, browser clients don't show a prompt to select a certificate for authentication.|
3636

3737
### [Azure portal](#tab/azureportal)
3838

39-
To use the Azure portal to set up your app to require client certificates:
39+
To use the Azure portal to enable client certificates:
4040

4141
1. Go to your app management page.
42-
1. On the left menu, select **Configuration** > **General Settings**.
42+
1. In the left menu, select **Configuration** > **General Settings**.
4343
1. For **Client certificate mode**, select your choice.
4444
1. Select **Save**.
4545

4646
### [Azure CLI](#tab/azurecli)
4747

48-
To use the Azure CLI, run the following command in [Azure Cloud Shell](https://shell.azure.com):
48+
To use the Azure CLI to enable client certificates, run the following command in [Azure Cloud Shell](https://shell.azure.com):
4949

5050
```azurecli-interactive
5151
az webapp update --set clientCertEnabled=true --name <app-name> --resource-group <group-name>
5252
```
5353

5454
### [Bicep](#tab/bicep)
5555

56-
For Bicep, modify the `clientCertEnabled`, `clientCertMode`, and `clientCertExclusionPaths` properties.
56+
To enable client certificates in Bicep, modify the `clientCertEnabled`, `clientCertMode`, and `clientCertExclusionPaths` properties.
5757

5858
Here's a sample Bicep snippet:
5959

@@ -76,7 +76,7 @@ resource appService 'Microsoft.Web/sites@2020-06-01' = {
7676

7777
### [ARM template](#tab/arm)
7878

79-
For Azure Resource Manager templates (ARM templates), modify the `clientCertEnabled`, `clientCertMode`, and `clientCertExclusionPaths` properties.
79+
To enable client certificates in an Azure Resource Manager template (ARM template), modify the `clientCertEnabled`, `clientCertMode`, and `clientCertExclusionPaths` properties.
8080

8181
Here's a sample ARM template snippet:
8282

@@ -110,56 +110,56 @@ When you enable mutual authentication for your application, all paths under the
110110
> [!NOTE]
111111
> Using any client certificate exclusion path triggers TLS renegotiation for incoming requests to the app.
112112
113-
1. On the left menu of your app management page, select **Configuration** > **General Settings**.
113+
1. In the left menu of your app management page, select **Configuration** > **General Settings**.
114114

115115
1. Next to **Certificate exclusion paths**, select the edit icon.
116116

117117
1. Select **New path**, specify a path or a list of paths separated by `,` or `;`, and then select **OK**.
118118

119119
1. Select **Save**.
120120

121-
In the following screenshot, any path for your app that starts with `/public` doesn't request a client certificate. Path matching isn't case specific.
121+
The following screenshot shows how to set a certificate exclusion path. Any path for the app that starts with `/public` doesn't request a client certificate. Path matching isn't case specific.
122122

123-
:::image type="content" source="media/app-service-web-configure-tls-mutual-auth/exclusion-paths.png" alt-text="Screenshot that shows setting a certificate exclusion path.":::
123+
:::image type="content" source="media/app-service-web-configure-tls-mutual-auth/exclusion-paths.png" alt-text="Screenshot that shows how to set a certificate exclusion path." lightbox="media/app-service-web-configure-tls-mutual-auth/exclusion-paths.png":::
124124

125125
## Client certificate and TLS renegotiation
126126

127-
For some client certificate settings, App Service requires TLS renegotiation to read a request before knowing whether to prompt for a client certificate. Any of the following settings triggers TLS renegotiation:
127+
For some client certificate settings, App Service requires TLS renegotiation to read a request before knowing whether to prompt for a client certificate. Both of the following settings trigger TLS renegotiation:
128128

129-
- Using the "Optional Interactive User" client certificate mode.
130-
- Using the [client certificate exclusion path](#exclude-paths-from-requiring-authentication).
129+
- Using the **Optional Interactive User** client certificate mode.
130+
- Using a [client certificate exclusion path](#exclude-paths-from-requiring-authentication).
131131

132132
> [!NOTE]
133133
> TLS 1.3 and HTTP 2.0 don't support TLS renegotiation. These protocols don't work if your app is configured with client certificate settings that use TLS renegotiation.
134134
135-
To disable TLS renegotiation and to have the app negotiate client certificates during TLS handshake, you must configure your app with *all* these settings:
135+
To disable TLS renegotiation and have the app negotiate client certificates during TLS handshake, you must take the following actions in your app:
136136

137-
1. Set the client certificate mode to **Required** or **Optional**.
138-
1. Remove all client certificate exclusion paths.
137+
- Set the client certificate mode to **Required** or **Optional**.
138+
- Remove all client certificate exclusion paths.
139139

140140
### Upload large files with TLS renegotiation
141141

142-
Client certificate configurations that use TLS renegotiation can't support incoming requests with large files greater than 100 KB due to buffer size limitations. In this scenario, any POST or PUT requests over 100 KB fails with a 403 error. This limit isn't configurable and can't be increased.
142+
Client certificate configurations that use TLS renegotiation can't support incoming requests with files that are larger than 100 KB. This limit is caused by buffer size limitations. In this scenario, any POST or PUT requests that are over 100 KB fail with a 403 error. This limit isn't configurable and can't be increased.
143143

144-
To address the 100-KB limit, consider these alternative solutions:
144+
To address the 100-KB limit, consider these solutions:
145145

146-
1. Disable TLS renegotiation. Update your app's client certificate configurations with *all* these settings:
146+
1. Disable TLS renegotiation. Take the following actions in your app's client certificate configurations:
147147
- Set the client certificate mode to **Required** or **Optional**.
148148
- Remove all client certificate exclusion paths.
149149
1. Send a HEAD request before the PUT/POST request. The HEAD request handles the client certificate.
150-
1. Add the header `Expect: 100-Continue` to your request. This causes the client to wait until the server responds with a `100 Continue` before sending the request body, which bypasses the buffers.
150+
1. Add the header `Expect: 100-Continue` to your request. This header causes the client to wait until the server responds with a `100 Continue` before sending the request body, and the buffers are bypassed.
151151

152152
## Access the client certificate
153153

154-
In App Service, TLS termination of the request happens at the front-end load balancer. When App Service forwards the request to your app code with [client certificates enabled](#enable-client-certificates), it injects an `X-ARR-ClientCert` request header with the client certificate. App Service doesn't do anything with this client certificate other than forward it to your app. Your app code is responsible for validating the client certificate.
154+
In App Service, TLS termination of the request happens at the front-end load balancer. When App Service forwards the request to your app code with [client certificates enabled](#enable-client-certificates), it injects an `X-ARR-ClientCert` request header with the client certificate. App Service doesn't do anything with this client certificate other than forward it to your app. Your app code needs to validate the client certificate.
155155

156-
For ASP.NET, the client certificate is available through the `HttpRequest.ClientCertificate` property.
156+
In ASP.NET, the client certificate is available through the `HttpRequest.ClientCertificate` property.
157157

158-
For other application stacks (Node.js, PHP), the client certificate is available in your app through a Base64-encoded value in the `X-ARR-ClientCert` request header.
158+
In other application stacks (Node.js, PHP), the client certificate is available via a Base64-encoded value in the `X-ARR-ClientCert` request header.
159159

160160
## ASP.NET Core sample
161161

162-
For ASP.NET Core, middleware is provided to parse forwarded certificates. Separate middleware is provided to use the forwarded protocol headers. Both must be present for forwarded certificates to be accepted. You can place custom certificate validation logic in the [CertificateAuthentication options](/aspnet/core/security/authentication/certauth).
162+
For ASP.NET Core, middleware is available to parse forwarded certificates. Separate middleware is available for using the forwarded protocol headers. Both must be present for forwarded certificates to be accepted. You can place custom certificate validation logic in the [CertificateAuthentication options](/aspnet/core/security/authentication/certauth):
163163

164164
```csharp
165165
public class Startup
@@ -174,20 +174,20 @@ public class Startup
174174
public void ConfigureServices(IServiceCollection services)
175175
{
176176
services.AddControllersWithViews();
177-
// Configure the application to use the protocol and client ip address forwarded by the front-end load balancer
177+
// Configure the application to use the protocol and client IP address forwarded by the front-end load balancer.
178178
services.Configure<ForwardedHeadersOptions>(options =>
179179
{
180180
options.ForwardedHeaders =
181181
ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto;
182-
// Only loopback proxies are allowed by default. Clear that restriction to enable this explicit configuration.
182+
// By default, only loopback proxies are allowed. Clear that restriction to enable this explicit configuration.
183183
options.KnownNetworks.Clear();
184184
options.KnownProxies.Clear();
185185
});
186186

187-
// Configure the application to client certificate forwarded the front-end load balancer
187+
// Configure the application to use the client certificate forwarded by the front-end load balancer.
188188
services.AddCertificateForwarding(options => { options.CertificateHeader = "X-ARR-ClientCert"; });
189189

190-
// Add certificate authentication so when authorization is performed the user will be created from the certificate
190+
// Add certificate authentication so that when authorization is performed the user will be created from the certificate.
191191
services.AddAuthentication(CertificateAuthenticationDefaults.AuthenticationScheme).AddCertificate();
192192
}
193193

@@ -224,7 +224,7 @@ public class Startup
224224
}
225225
```
226226

227-
## ASP.NET WebForms sample
227+
## ASP.NET Web Forms sample
228228

229229
```csharp
230230
using System;
@@ -248,8 +248,8 @@ public class Startup
248248
public bool isValidCert = false;
249249

250250
//
251-
// Read the certificate from the header into an X509Certificate2 object
252-
// Display properties of the certificate on the page
251+
// Read the certificate from the header into an X509Certificate2 object.
252+
// Display properties of the certificate on the page.
253253
//
254254
protected void Page_Load(object sender, EventArgs e)
255255
{
@@ -286,19 +286,19 @@ public class Startup
286286
}
287287

288288
//
289-
// This is a SAMPLE verification routine. Depending on your application logic and security requirements,
290-
// you should modify this method
289+
// This is a sample verification routine. You should modify this method to suit your application logic and security requirements.
290+
//
291291
//
292292
private bool IsValidClientCertificate()
293293
{
294-
// In this example, we accept the certificate as a valid certificate only if all the conditions below are met:
294+
// In this example, the certificate is accepted as a valid certificate only if these conditions are met:
295295
// - The certificate isn't expired and is active for the current time on the server.
296296
// - The subject name of the certificate has the common name nildevecc.
297297
// - The issuer name of the certificate has the common name nildevecc and the organization name Microsoft Corp.
298298
// - The thumbprint of the certificate is 30757A2E831977D8BD9C8496E4C99AB26CB9622B.
299299
//
300-
// This example doesn't test that this certificate is chained to a Trusted Root Authority (or revoked) on the server
301-
// and it allows for self-signed certificates.
300+
// This example doesn't test that the certificate is chained to a trusted root authority (or revoked) on the server.
301+
// It allows self-signed certificates.
302302
//
303303
304304
if (certificate == null || !String.IsNullOrEmpty(errorString)) return false;
@@ -359,26 +359,26 @@ import { pki, md, asn1 } from 'node-forge';
359359
export class AuthorizationHandler {
360360
public static authorizeClientCertificate(req: Request, res: Response, next: NextFunction): void {
361361
try {
362-
// Get header
362+
// Get header.
363363
const header = req.get('X-ARR-ClientCert');
364364
if (!header) throw new Error('UNAUTHORIZED');
365365

366-
// Convert from PEM to pki.CERT
366+
// Convert from PEM to PKI certificate.
367367
const pem = `-----BEGIN CERTIFICATE-----${header}-----END CERTIFICATE-----`;
368368
const incomingCert: pki.Certificate = pki.certificateFromPem(pem);
369369

370-
// Validate certificate thumbprint
370+
// Validate certificate thumbprint.
371371
const fingerPrint = md.sha1.create().update(asn1.toDer(pki.certificateToAsn1(incomingCert)).getBytes()).digest().toHex();
372372
if (fingerPrint.toLowerCase() !== 'abcdef1234567890abcdef1234567890abcdef12') throw new Error('UNAUTHORIZED');
373373

374-
// Validate time validity
374+
// Validate time validity.
375375
const currentDate = new Date();
376376
if (currentDate < incomingCert.validity.notBefore || currentDate > incomingCert.validity.notAfter) throw new Error('UNAUTHORIZED');
377377

378-
// Validate issuer
378+
// Validate issuer.
379379
if (incomingCert.issuer.hash.toLowerCase() !== 'abcdef1234567890abcdef1234567890abcdef12') throw new Error('UNAUTHORIZED');
380380

381-
// Validate subject
381+
// Validate subject.
382382
if (incomingCert.subject.hash.toLowerCase() !== 'abcdef1234567890abcdef1234567890abcdef12') throw new Error('UNAUTHORIZED');
383383

384384
next();
@@ -416,9 +416,9 @@ public class ClientCertValidator {
416416

417417
/**
418418
* Constructor.
419-
* @param certificate The certificate from the "X-ARR-ClientCert" HTTP header
420-
* @param thumbprint The thumbprint to check against
421-
* @throws CertificateException If the certificate factory cannot be created.
419+
* @param certificate. The certificate from the "X-ARR-ClientCert" HTTP header.
420+
* @param thumbprint. The thumbprint to check against.
421+
* @throws CertificateException if the certificate factory can't be created.
422422
*/
423423
public ClientCertValidator(String certificate, String thumbprint) throws CertificateException {
424424
certificate = certificate
@@ -434,16 +434,16 @@ public class ClientCertValidator {
434434

435435
/**
436436
* Check that the certificate's thumbprint matches the one given in the constructor, and that the
437-
* certificate hasn't expired.
438-
* @return True if the certificate's thumbprint matches and hasn't expired. False otherwise.
437+
* certificate isn't expired.
438+
* @return True if the certificate's thumbprint matches and isn't expired. False otherwise.
439439
*/
440440
public boolean certificateIsValid() throws NoSuchAlgorithmException, CertificateEncodingException {
441441
return certificateHasNotExpired() && thumbprintIsValid();
442442
}
443443

444444
/**
445445
* Check certificate's timestamp.
446-
* @return Returns true if the certificate hasn't expired. Returns false if it has expired.
446+
* @return returns True if the certificate isn't expired. It returns False if it is expired.
447447
*/
448448
private boolean certificateHasNotExpired() {
449449
Date currentTime = new java.util.Date();
@@ -456,8 +456,8 @@ public class ClientCertValidator {
456456
}
457457

458458
/**
459-
* Check the certificate's thumbprint matches the given one.
460-
* @return Returns true if the thumbprints match. False otherwise.
459+
* Check whether the certificate's thumbprint matches the given one.
460+
* @return returns True if the thumbprints match. False otherwise.
461461
*/
462462
private boolean thumbprintIsValid() throws NoSuchAlgorithmException, CertificateEncodingException {
463463
MessageDigest md = MessageDigest.getInstance("SHA-1");
@@ -468,7 +468,7 @@ public class ClientCertValidator {
468468
return digestHex.toLowerCase().equals(this.getThumbprint().toLowerCase());
469469
}
470470

471-
// Getters and setters
471+
// Getters and setters.
472472

473473
public void setThumbprint(String thumbprint) {
474474
this.thumbprint = thumbprint;
@@ -490,7 +490,7 @@ public class ClientCertValidator {
490490

491491
## Python sample
492492

493-
The following Flask and Django Python code samples implement a decorator named `authorize_certificate` that can be used on a view function to permit access only to callers that present a valid client certificate. It expects a PEM formatted certificate in the `X-ARR-ClientCert` header and uses the Python [cryptography](https://pypi.org/project/cryptography/) package to validate the certificate based on its fingerprint (thumbprint), subject common name, issuer common name, and beginning and expiration dates. If validation fails, the decorator ensures that an HTTP response with status code 403 (Forbidden) is returned to the client.
493+
The following Flask and Django Python code samples implement a decorator named `authorize_certificate` that can be used on a view function to permit access only to callers that present a valid client certificate. It expects a PEM-formatted certificate in the `X-ARR-ClientCert` header and uses the Python [cryptography](https://pypi.org/project/cryptography/) package to validate the certificate based on its fingerprint (thumbprint), subject common name, issuer common name, and beginning and expiration dates. If validation fails, the decorator ensures that an HTTP response with status code 403 (Forbidden) is returned to the client.
494494

495495
### [Flask](#tab/flask)
496496

@@ -538,7 +538,7 @@ def validate_cert(request):
538538
return True
539539

540540
except Exception as e:
541-
# Handle any errors encountered during validation
541+
# Handle any errors encountered during validation.
542542
print(f"Encountered the following error during certificate validation: {e}")
543543
return False
544544

@@ -607,7 +607,7 @@ def validate_cert(request):
607607
return True
608608

609609
except Exception as e:
610-
# Handle any errors encountered during validation
610+
# Handle any errors encountered during validation.
611611
print(f"Encountered the following error during certificate validation: {e}")
612612
return False
613613

0 commit comments

Comments
 (0)