JakeUT
JakeUT

Reputation: 527

Azure API Management get user identity?

This may not be supported but I was thinking about a scenario such as this. Lets say there is an internal endpoint that uses AD authentication. If one were to route an Azure APIM call to this backend, is there a way to get the end user who may have initiated the call to the APIM endpoint? Or is this not the scenario it was meant for? Is APIM meant more for application-to-application type calls and not necessarily something an enduser might initiate?

Thanks in advance, Jake.

Upvotes: 2

Views: 4966

Answers (1)

Hury Shen
Hury Shen

Reputation: 15734

For your requirement, I did lots of test for it. Please refer to my steps below:

As the endpoint uses AD authentication, so user needs to provide a token when request the APIM(to request the endpoint). So we can know the user name by decode the token which provided when request the APIM. Before do it, you need to know only when the user use a grant flow like username/password flow or auth code flow, the token can include user identity. If the user use a grant flow like client credential flow to get the token, the token will not include user identity. So in my solution I assume user use username/password flow or auth code flow to get the token.

The I did some test, I want to get the token in request header of APIM. So I configure "Diagnostic settings" of APIM to stream logs to azure storage(or event hub). Then query the logs in "Logs" tab of APIM. But I found we can not see the headers of the request in the logs, both RequestHeaders and BackendRequestHeaders fields are empty (shown in below screenshot).

enter image description here

So I don't think we can get user identity according to the token by normal solution.

But here I provide a workaround for your reference:

I created a azure function with default code, and just add one line. enter image description here

Then I added a policy in APIM inbound block.

<policies>
    <inbound>
        <base />
        <send-request mode="new" response-variable-name="tokenstate" timeout="20" ignore-error="true">
            <set-url>https://huryxxxxtestfun.azurewebsites.net/api/HttpTrigger6</set-url>
            <set-method>POST</set-method>
            <set-header name="Content-Type" exists-action="override">
                <value>application/json</value>
            </set-header>
            <set-body>@{
                string authHeader = context.Request.Headers.GetValueOrDefault("Authorization", "");
                string name = "unknown";
                if (authHeader?.Length > 0)
                {
                    string[] authHeaderParts = authHeader.Split(' ');
                    if (authHeaderParts?.Length == 2 && authHeaderParts[0].Equals("Bearer", StringComparison.InvariantCultureIgnoreCase))
                    {
                        Jwt jwt;
                        if (authHeaderParts[1].TryParseJwt(out jwt))
                        {
                            name = (jwt.Claims.GetValueOrDefault("name", "unknown"));
                        }
                    }
                }
                return new JObject(new JProperty("name",name)).ToString();
            }</set-body>
        </send-request>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

The <send-request> policy is used to request the azure function url. I decode the token in policy and get the user name, send the name to azure function. Then we can see the user name in azure function log. enter image description here

By the way, we can also get object id of the user by modify the code name = (jwt.Claims.GetValueOrDefault("name", "unknown")); to name = (jwt.Claims.GetValueOrDefault("oid", "unknown")); in policy.

Upvotes: 2

Related Questions