Scrum Masters

Using ADFS with Azure API Management

.
.(* )Azure API Management is an API entrance that can be utilized to release APIs to the Web. It supplies functions such as per-developer API secrets, demand throttling and demand authentication. Among the method demands can be validated is through basic OAuth2 bearer tokens. I presume that the most typical circumstance is to utilize Azure advertisement to provide those tokens. However if an organisation is not that cloud allowed yet and the users remain in an on prem advertisement, the natural token provider is to utilize ADFS. And ADFS on Windows Server 2016 supports OpenID Link, so it should work, right?

Well, it ends up it didn’t simply work. The OpenID Link application in ADFS has some peculiarities that require to be dealt with. In the end it worked, however with some constraints.

Among the cool things with OpenID Link is that it supplies a metadata based convention for setup. There’s no requirement to download and deal with certificates to sign up finalizing secrets, it usually simply works. Up until it does not. Which held true here.

Initially, the setup in the Azure API Management Policy was relatively simple. The policy checks that a matched question string criterion

colour from the general public dealing with URL is likewise present as a claim. This brings all the method to the active directory site user item, where the "other pager" field was utilized to note the colours that a particular user is permitted to utilize in the URL to the API.<< policies

>><< incoming
  >><< validate-jwt
     header-name  =" Permission">><< openid-config
       url  ="/>> << required-claims
      >><< claim
         name  =" colour" match  =" all">><< worth
          >> @(( string) context.Request.MatchedParameters)["colour"]<<<
        <<< base
      />><
    << backend>>
    << base />>
  <<< outbound
  >><< base
    />> <
  << on-error>>
  << base/>>
    < <
  << policies>
> 
. < incoming>
> 
. < validate-jwt header-name=" Permission">
<> 
 < openid-config url= ">
/
<> 
. < required-claims > 
<. < claim name=" colour" match=" all">
<> 
>< worth > @(( string) context.Request.MatchedParameters)< 
.  
.  
.  
. < base/>
> 
.  
. < backend>
> 
. < base/>
> 
.  
. < outgoing>
> 
. < base/>
> 
.  
. < on-error>
> 
. < base/>
> 
.  
. 
   This code ended up to operate in completion, after some workarounds had actually been used. The very first issue was apparent when I utilized jwt.io to check the gain access to token I got from the ADFS. It didn't include the asked for 
     colours  scope and didn't include the 
   colours claims.
 {

." aud":" urn: microsoft: userinfo",

." iss":"." iat": 1511714437, 
." exp": 1511718037,

." apptype":" Public", 
." appid":" 8059f5ed-fa9b-4165-815c-663dec49b965",

.
" authmethod": "urn: sanctuary: names: tc: SAML:2.0: a/c: classes: undefined
", 
. "auth_time": "2017-11-26T16:40:36.000 Z
", 
.
" ver": "1.0", 
." scp": "openid",

." sub":" r5PvRoaOXFmaJ+ q6LyeVslYVXZl38F/UkrBvQNlyoY8=" 
} {
.
" aud": "urn: microsoft: userinfo",

." iss":"." iat": 1511714437, 
." exp": 1511718037, 
."
apptype":" Public", 
." appid": "8059f5ed-fa9b-4165-815c-663dec49b965", 
." authmethod":" urn: sanctuary: names: tc: SAML:2.0: a/c: classes: undefined ", 
." auth_time ":" 2017-11-26T16:40:36.000 Z", 
." ver":" 1.0 ", 
. "scp ":" openid ", 
. "sub ":" r5PvRoaOXFmaJ + q6LyeVslYVXZl38F/UkrBvQNlyoY8 =" 
} 

{
.” aud”:”.” iss”:”.” iat”: 1511718387, .” exp”: 1511721987, .” colour”:” Blue”, .” apptype”:” Public”, .” appid” :
” 8059f5ed-fa9b-4165-815c-663dec49b965″, .
” authmethod”: “urn: sanctuary: names: tc: SAML :2.0: a/c: classes: undefined”, .” auth_time”: ” 2017-11-26T17:46:24.000 Z”, .” ver”:” 1.0″, .” scp”:” colours
” .
}

{ .” aud”: “.” iss”:”. “iat”: 1511718387, .” exp”: 1511721987, .” colour”:” Blue”, .” apptype”:” Public”, .” appid “:” 8059f5ed-fa9b-4165-815c-663dec49b965 “, .” authmethod “: “urn: sanctuary: names: tc: SAML:2.0: a/c: classes: undefined”, . “auth_time”:” 2017-11-26T17:46:24.000 Z “, .” ver”:” 1.0″, .” scp”:” colours” .} So it ends up that ADFS is providing various gain access to tokens for various APIs and the method to ask for a gain access to token for a particular API is to utilize the non-standard (* )resource criterion. I’ll compose some more on this in another post. In the meantime, simply let's proceed with the work and attempt to utilize the gain access to token to access the API. At the very first shot with my brand-new gain access to token, things simply didn’t work. Discovering why wasn’t apparent. I copied the gain access to token I had actually got in my customer application into the API test tools in the Azure website to get a trace. The trace simply exposes that the JWT recognition stopped working. To get the real JWT recognition mistake, one needs to follow the link that’s noted in the trace. Because log, the mistake message is clear (congratulations to the Microsoft dev who chose to consist of the real worths in the exception message).

 message:" JWT Recognition Stopped Working: IDX10205: Company recognition stopped working. Company:' Did not match: validationParameters.ValidIssuer: "or validationParameters.ValidIssuers: '.

iss field of the JWT does not match the one in noted in the OpenID Link setup details. Taking a look at the ADFS OpenID Link setup details readily available at revealed another non-standard OpenID Link behaviour of ADFS. At the top, an

 provider

is revealed. This likewise represents the OpenID Link requirement that the setup file course is formed by concatenating the provider URL with

/. well-known/openid-configuration

The id_token properly includes

 as provider. Nevertheless, that's not the provider discovered in the gain access to token. The gain access to token utilizes the ID I have actually established in ADFS as the Federation Service Identifier. That's the worth utilized as the Entity ID in SAML-based tokens. Which identifier is really present in the metadata in the non-standard field 

access_token_issuer { .
” provider”:” “, .” authorization_endpoint”: “/ oauth2/authorize/”, .” token_endpoint”: ”/ oauth2/token/”, .” jwks_uri”:”/ discovery/keys”, .” token_endpoint_auth_methods_supported”:, .” response_types_supported”: , ." response_modes_supported":, .” grant_types_supported”:, .” subject_types_supported”: , ." scopes_supported ":
, .” id_token_signing_alg_values_supported”: , ." token_endpoint_auth_signing_alg_values_supported":, .” access_token_issuer ”:”.” claims_supported”:, .” microsoft_multi_refresh_token”: real, .” userinfo_endpoint”:”/ userinfo”, .” abilities”: , ." end_session_endpoint":"/ oauth2/logout", ." as_access_token_token_binding_supported": real, ." as_refresh_token_token_binding_supported "
: real, . " resource_access_token_token_binding_supported ": real, ." op_id_token_token_binding_supported": real, ." rp_id_token_token_binding_supported": real, ." frontchannel_logout_supported": real ,
." frontchannel_logout_session_supported": real .}
{ .” provider ”:””, .” authorization_endpoint”:”/ oauth2/authorize/”, .” token_endpoint”:”/ oauth2/token/”, .” jwks_uri”:”/ discovery/keys”, .” token_endpoint_auth_methods_supported”:

, 
.
" response_types_supported":[
    "client_secret_post",
    "client_secret_basic",
    "private_key_jwt",
    "windows_client_authentication"
  ], 
." response_modes_supported":[
    "code",
    "id_token",
    "code id_token",
    "id_token token",
    "code token",
    "code id_token token"
  ], 
." grant_types_supported":[
    "query",
    "fragment",
    "form_post"
  ], 
." subject_types_supported":[
    "authorization_code",
    "refresh_token",
    "client_credentials",
    "urn:ietf:params:oauth:grant-type:jwt-bearer",
    "implicit",
    "password",
    "srv_challenge"
  ], 
." scopes_supported ":[
    "pairwise"
  ],

." id_token_signing_alg_values_supported":[
    "aza",
    "logon_cert",
    "user_impersonation",
    "winhello_cert",
    "profile",
    "email",
    "allatclaims",
    "vpn_cert",
    "openid",
    "colours"
  ], 
." token_endpoint_auth_signing_alg_values_supported ":[
    "RS256"
  ],

." access_token_issuer":".
" claims_supported":[
    "RS256"
  ], 
." microsoft_multi_refresh_token": real, 
." userinfo_endpoint":"/ userinfo", 
." abilities":[
    "aud",
    "iss",
    "iat",
    "exp",
    "auth_time",
    "nonce",
    "at_hash",
    "c_hash",
    "sub",
    "upn",
    "unique_name",
    "pwd_url",
    "pwd_exp",
    "sid"
  ], 
." end_session_endpoint":"/ oauth2/logout", 
." as_access_token_token_binding_supported": real, 
." as_refresh_token_token_binding_supported": real, 
." resource_access_token_token_binding_supported": real, 
." op_id_token_token_binding_supported": real, 
." rp_id_token_token_binding_supported": real, 
." frontchannel_logout_supported": real, 
." frontchannel_logout_session_supported": real

.}[] Obviously not even Microsoft's own API Management platform learns about that field. So the inbound gain access to token is declined by Azure API Management due to provider names not matching. Initially I attempted to fix that by manually including the gain access to token provider worth in the API Management policy, however I never ever got it working (I believe it was something with an inaccurate routing area included). Rather I returned and relabelled my ADFS server, so that the Federation Service Identifier now is 

concern. In a fresh ADFS setup that’s possible through a rename. In an existing environment most likely not. What’s more extreme is that to get the gain access to token the additional resource criterion need to be included. Microsoft’s OpenID Link handler for ASP.NET Core 2 supports that and their ADAL.js library for javascript does. However other standard-conforming libraries such as Brock Allen’s oidc-client. js or libaries for non-. Web server side applications will not work. And the whole function of the API Management platform is to release APIs on the Web for other designers to utilize. Utilizing an OpenID Link Service provider that needs non-standard behaviour of the customer will undoubtedly produce compatibility problems in such a situation. .
Published in . Azure on 2017-12-06|Tagged ADFS, OpenID Link
.
.
.
.

.