How to apply different authentication mechanism in single proxy based on consumer requirement

Not applicable

Hi All,

We have a proxy created for multiple consumers, need to enable different authentication mechanism based on consumer as all consumer do not support same authentication methods. some consumers support oAuth2.0 and others support client certificate authentication or IP white-listing.

As client certificate authentication should be enabled at virtual host, if some consumer do not support client certificate authentication. is it possible to disable client certificate authentication for specific consumer?

please share if Apigee provides any out of box policy to verify certificate name, CA and other client certificate parameters at proxy level.

We want to implement IP white-listing in proxy for one consumer who do not support client certificate authentication and we do not want to apply this for other consumers. is it possible to apply access control policy for specific consumer?

Regards,

Rathnakar

1 1 612
1 REPLY 1

Yes, you can do what you describe.

To allow some consumers to present a client cert, and others to present an OAuth2 token, you will need to use distinct virtual hosts.

2waytls.apis.mycompany.com this vhost requires a client cert. 2-way TLS enabled. You will probably want to propagate information for the client's TLS cert into the proxy, in order to further validate it.
apis.mycompany.com allows oauth2 tokens. (Or API keys if you like)

Configure your API Proxy to listen on both vhosts. Then, based on the vhost, perform the appropriate authentication.

<Step>
  <Condition>(virtualhost.name != "2wayTLS") and (virtualhost.name != "oauth2")</Condition>
  <Name>RaiseFault-InvalidAuthentication</Name>
</Step>
<Step>
  <Condition>virtualhost.name = "2wayTLS"</Condition>
  <Name>VerifyApiKey</Name>
</Step>
<Step>
  <Condition>virtualhost.name = "oauth2"</Condition>
  <Name>OAuth2-VerifyAccessToken</Name>
</Step>

But then you need one further step.... you need to verify that the client app in question is using the correct vhost. (I'm assuming you want to restrict client apps to using a specific vhost).

You can specify that restriction with a custom attribute on the API Product, that stipulates whether the client in question ought to be using OAuth2 or client certs.

7099-vhost-custom-attr.png

Remember, each consumer app is authorized on a specific API product. Therefore AFTER validating the key or token in the proxy flow, you can check that the apiproduct attribute matches the required vhost. Like this:

<Step>
  <Condition>apiproduct.required-vhost != virtualhost.name</Condition>
  <Name>RaiseFault-InvalidAuthentication</Name>
</Step>

That context variable, apiproduct.required-vhost, is implicitly loaded after you verify the credentials.

For the 2way TLS case, you may wish to perform further validation of the client DN, or fingerprint, etc. To do that you could use a custom attribute on the specific client app that stores the required fingerprint, in a way similar to that shown above for the custom attribute on the API Product.

To get the client TLS fingerprint, you need to configure the vhost to propagate client properties for TLS. See this documentation. Then you would do something like this:

<Step>
  <Condition>verifyapikey.VAK-1.client_fingerprint != tls.client.cert.fingerprint</Condition>
  <Name>RaiseFault-InvalidClientCertificate</Name>
</Step>

So it's not a "policy" you would use to verify the client cert information, but just a Condition.

For the IP whitelist, I assume the whitelist is dynamic and set inside another custom attr on the client app. In that case you could do that with a JS policy wrapped in a condition.

<Step>
  <Condition>virtualhost.name = "oauth2"</Condition>
  <Name>JS-EnforceIpWhitelist</Name>
</Step>

<Step>
  <Condition>(virtualhost.name = "oauth2") && (ip_OK = false) </Condition>
  <Name>RaiseFault-InvalidClientIp</Name>
</Step>

And the JS code would do something like this:

var clientIp = context.getVariable('proxy.client.ip ');
var ipList = context.getVariable('apiproduct.ip_list').split(',');
var found = ipList.find(function(candidate) { return candidate == clientIp; });
context.setVariable('ip_OK', found ? true : false);