Tuesday, April 26, 2022

#908 OIC & OAuth 2.0 - Part 3

In this final post on this theme, I will discuss the authorizer function, that will validate the client token and invoke IDCS to generate a new OIC token. This function will be called from API Gateway, which takes the result and injects the new token into the Authorization Header, before routing the request to OIC. The latter will then be injected into the original request, which is then forwarded to OIC.












An introduction to the authorization function can be found here in the API Gateway docs.

Net, net, the code will be written in python, and there are examples already available, thanks to some of my Oracle colleagues. In fact there are how to's already available out there on OIC and OAuth, however, sometimes details are missing. And, as you all know, the devil lies in the detail. This series of posts has been written with neophytes in mind, i.e. my audience are not expected to be experts in IDCS, OCI Functions etc.- simply folks who need to protect their public facing OIC endpoints. I got a great deal of help from my colleagues so - 

A big thank you here to Valeria Chiran and Robert Wunderlich!

Let the show begin...

IDCS Configuration

I begin by creating the OIC app in IDCS - 




 







I also create an app, to be used for validating the client token - it is configured as follows - 
















I can try the introspection invoke in Postman - 
The default IDCS IRL is - 
https://yourIDCS/oauth2/v1/introspect

Here is the invoke is Postman -

Firstly, I get a token for the admin -










Then I use it as follows - set token to new access token value.













The introspect request uses Basic Auth (user/pwd set to clientId / secret)















This is the client id and secret from the IDCS App - AA-Salary-application-introspection.
 

OCI Vault

This is used to securely store the client secrets -











Pre-requisite IDCS Policies

We have here api gateway invoking functions, functions invoking OCI Vault etc.So we need to apply some policies so this will work.

I create the following policy at root level -


 
 


The following policies were created in my compartment containing api gateway etc. -






apiGtyVaultPolicy - 

Allow any-user to use secret-family in compartment yourCompartment where ALL {request.principal.type = 'ApiGateway', request.resource.compartment.id = 'yourCompartmentOCID'}

Allow any-user to use secret-family in compartment yourCompartment where ALL {request.principal.type = 'fnfunc', request.resource.compartment.id = 'yourCompartmentOCID'}

fnVCNPolicy -

Allow service FaaS to use virtual-network-family in compartment yourCompartment

APIGtwyFnPolicy -

ALLOW any-user to use functions-family in compartment yourCompartment where ALL {request.principal.type = 'ApiGateway', request.resource.compartment.id = 'yourCompartmentOCID'}


Creating the Authorizer Function

This will essentially do what we have already tested in Postman.

To re-iterate, the function will do the following -
1. validate the incoming client token via IDCS
2. If token is valid then get a new access token for OIC from IDCS.
3. Function Configuration keys will be created for variables such as client ids, secrets, introspection url etc. The secrets will be stored in OCI Vault, so the variables will contain the ocids of those secrets.  

Again, a big thanks to my colleague Valeria Chiran for the function code.

The code is available on gitHub -













The main authorizer code is in func.py
ociVault.py gets/decrypts the secrets.

requirements.txt lists the required libraries.

So let's create the function -
 




cmd to create python function is as follows -
fn init --runtime python myCustomAuthorizer4OIC

Check out what's been generated -




Copy and paste the func.py code -









Notice the use of context variables - this refers to the Function Configuration keys, mentioned earlier.
Create a new file ociVault.py e.g. nano ociVault.py
Copy and paste the code from ociVault.py 

Ensure the requirements.txt contains the following entries -




 




Deploy the Function - 
fn -v deploy --app apiGtwyCustomAuthorizer

wait for the Successfully created message.



























Back to the context variables - you can go thru the code and pick these out. However, here they are -














idcs_introspection_endpoint
apigw_idcs_app_client_id
apigw_idcs_app_client_secret_ocid
idcs_token_endpoint
oic_idcs_app_client_id
oic_idcs_app_client_secret_ocid
oic_scope

These are mainly self-explanatory, but, just in case -

The idcs_introspection_endpoint is called to validate the original client token that is passed to api gateway.

The apigw_cs_app_client_id and apigw_cs_app_client_secret_ocid refer to the client id and secret of the IDCS App - AA-Salary-application-introspection.

The oic_idcs_app_client_id and oic_idcs_app_client_secret_ocid refer to the client id and secret of the IDCS App - AA-Salary-application-OIC.

The idcs_token_endpoint is called to generate the OIC access token. 

We can test the function in the CLI, all we need is a valid token - this we can generate from Postman -



















echo -n '{"token":"Bearer token"}' | fn invoke apiGtwyCustomAuthorizer mycustomauthorizer4oic | jq .

The result - 














great - so that's working, now to invoking the function from API Gateway.

Configure API Gateway to invoke custom authorizer 

I amend the OIC_AA_SALARY_ADMINS deployment as follows - 




































That's the function invoked, now to swapping the token - 















Value is set to ${request.auth[back_end_token]}

Now let's test this - and there it is - the response from OIC -






















Let's check out the logs

Function logs - 















API Gateway logs - 















Monday, April 25, 2022

#907 OIC & OAuth 2.0 Part 2


This is what I hope to implement over the next 2 posts. 











Here I restrict access to OIC endpoints, using OCI API Gateway. The flow is as follows - 
Client invokes API with OAuth token for the API.  API Gateway receives the token and then invokes a custom authorizer function. This function validates the token, then retrieves the OIC token. This is returned to API Gateway, which then replaces the original token in the request header. The request is then routed to OIC.

A big thank you to my colleague Valeria Chiran for her support here!

The previous post covered the OAuth setup at IDCS level. It ended with a test of the OIC endpoint from Postman, using the access token retrieved from IDCS. 
OIC customers value OCI API Gateway for many reasons, including the following -

1. Endpoint Virtualisation

2. Making it easy to expose a subset of integration endpoints to various clients - this could include 3rd parties.

3. Easy integration with 3rd party identity providers.

4. Ability to leverage a rich set of API Gateway policies - rate limiting etc.

For me, the focus will be on granting access to the following integrations -


AA-Salary-Test-MV supports multiple verbs - GET (get the salary based on empid) and PUT (update salary based on empid).

The rules are very simple - I have 2 sets of clients - users and admins. The users can read salary info, the admins can update salary info. 

Net, net - users should be able to invoke the OIC integration AA-SALARY-USERS as well as the GET on AA-SALARY-Test-MV. The admins should be able to invoke all endpoints. Let's begin by looking at the multiple verb integration - 






Let's agree to use 2 different scopes to enforce the rules - _userScope and _adminScope.

Many OIC customers require something similar, e.g. different trading partners requiring access to different sets of integrations. I have greatly simplified things here with my 3 integrations, but they will suffice to demonstrate the value-add of the combination API Gateway / IDCS.  

Deploy the multi verb integration to API Gateway




 



























Check out the routing rules - 









Add a new routing rule /version












Try invoking /version from Postman -








Note no auth has been set.

Back to the API Gateway - let's secure the api by setting the authentication as follows - 





























Note the use of IDCS as the Issuer.













Click Show Advanced Options -

Here I add my 2 scopes -














Validate in IDCS that clients can access the signing certificate - specified above in the Public Keys section.






Now we move to IDCS... 

Creating the required applications in IDCS

This is where the magic happens - 












Let's go thru these individually - 

AA-Salary-application - this takes care of the resources/scopes.














Note the definition of the 2 scopes _userScope, _adminScope.

AA-Salary-application-admins - this is specifically for admin clients.






















Note the scope setting - anyAudience_adminScope

This is a concatenation of ALLOWED AUDIENCES and the relevant CLAIM VALUE.

Think back to the Authentication definition in API Gateway - 















A client Id and secret are generated. 


I do the same for the users - AA-Salary-application-users - same as the above except for - 







I also save the client id and secret generated - 










 


I test the /version endpoint again from Postman - 







As expected - Unauthorized.

Now I add the OAuth client details from the "users" app -


 








Token config is as follows - 










Access Token URL set to https://myIDCSURL/oauth2/v1/token

So now we have successfully tested limiting access to only authorised clients - OAuth 2.0 Authorization on OCI API Gateway, courtesy of IDCS.

I now publish the 2 remaining OIC endpoints to API Gateway -

Beginning with the admin only integration - AA-Salary-Admins -







Here I add the same Authentication rule - 















I add another route - /version - with the same stock response as in the previous example.











I test this with the client credentials from user









Now with the admin credentials - 








Summary

This post has shown how easy it is to protect API Gateway apis via OAuth 2.0. It detailed the resources required at IDCS level to make this work. Next step is to create the IDS app for OIC access as well as the custom authorizer function - work for the next post!