skip to Main Content

I have created some Azure function apps and imported them to APIM, where they work fine. But I have a problem with some APIs that use certificate authentication. When I access the APIM Developer Portal for the first time and try to test an API that does not need a certificate, the browser still asks me to select a certificate.

is this is expected scenario?

Inbound policy of API that have certificate authentication:

    <inbound>
        <base />
        <choose>
            <when condition="@(context.Request.Certificate == null || !context.Deployment.Certificates.Any(c => c.Value.Thumbprint == context.Request.Certificate.Thumbprint))">
                <return-response>
                    <set-status code="403" reason="Invalid client certificate" />
                </return-response>
            </when>
            <otherwise />
        </choose>
        <authentication-certificate certificate-id="DevCert" />
        <set-backend-service id="apim-generated-policy" backend-id="sample-func" />
    </inbound>

Inbound policy of API that DOES NOT HAVE certificate authentication:

    <inbound>
        <base />
        <set-backend-service id="apim-generated-policy" backend-id="sample-func" />
    </inbound>

2

Answers


  1. When I access the APIM Developer Portal for the first time and try to test an API that does not need a certificate, the browser still asks me to select a certificate. Is this expected scenario?

    No, this is not the expected case. You shouldn’t get the option to select the certificate for the API which is not having authentication-certificate policy in it unless you have added the policy in global level or in product level and have attached that product to the API.

    I have imported an Azure function to the APIM instance and it is having two operations(GET, POST) in it.

    Policy of GET operation looks like below-

    <policies>
        <inbound>
            <base />
            <choose>
                <when condition="@(context.Request.Certificate == null || !context.Deployment.Certificates.Any(c => c.Value.Thumbprint == context.Request.Certificate.Thumbprint))">
                    <return-response>
                        <set-status code="403" reason="Invalid client certificate" />
                    </return-response>
                </when>
                <otherwise />
            </choose>
            <authentication-certificate certificate-id="DevCert" />
            <set-backend-service id="apim-generated-policy" backend-id="afreen-fa-1" />
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <base />
        </outbound>
        <on-error>
            <base />
        </on-error>
    </policies>
    

    enter image description here

    Policy of POST operation looks like below-

    <policies>
        <inbound>
            <base />
            <set-backend-service id="apim-generated-policy" backend-id="afreen-fa-1" />
        </inbound>
        <backend>
            <base />
        </backend>
        <outbound>
            <base />
        </outbound>
        <on-error>
            <base />
        </on-error>
    </policies>
    

    enter image description here

    Then I published the developer portal and trying to access these operations.

    GET Operation

    enter image description here

    POST Operation

    Not being asked to select the certificate even if I am trying to access the Post operation prior.

    enter image description here

    Verify your policies and publish the developer portal after making the changes.

    Login or Signup to reply.
  2. This is normal browser behavior when mutual authentication is involved, and is not APIM specific. Client certificate can either be provided at the time connection is created or later during re-negotiation process when server requests one. But in both cases it is common browser behavior to prompt user for a certificate while still allowing to press Cancel and provide none.

    There are two places in APIM where you can control this behavior, first is in custom hostname properties where you can check "Negotiate client certificate" option. If checked it will prompt client for certificate whenever new connection is being established to make a request. Probably not what you want.

    Second option is to read context.Request.Certificate. If referenced in policy expressions this triggers re-negotiation process and will request certificate from client, which browsers would treat by showing corresponding UI. Unfortunately there is nothing in protocol that would indicate upfront that client does not have a certificate and would prevent browser from showing selection UX.

    In both cases this happens only once per connection as browsers generally maintain connections to websites to future requests and also remember your certificate choise for the duration of client session.

    The only way to avoid it would be to make sure that "Negotiate client certificate" option is disabled on your hostname (including default one), and to make sure you only read context.Request.Certificate only when necessary. One way to do this is to wrap your choose policy with another one to make sure that context.Request.Certificate is referenced only when necessary, i.e. if call is made to specific API, or over specific domain, or not made from Developer portal. For the latter you can do something like below:

    <choose>
        <when condition="@(context.Request.Headers.GetValueOrDefault("Referer") != "afreen-apimgmt-01.developer.azure-api.net">
            ... check for certificate here ...
        </when>
    </choose>
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search