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 - 















No comments: