Skip to content

1. Development

Gary Archer edited this page Nov 2, 2022 · 30 revisions

Prerequisites

A C compiler must be installed that meets the ISO C Standard (C99), such as gcc.
On macOS, the C compiler installed by XCode works fine.
Also ensure that a Docker engine and the jq tool are installed.

1. Install an IDE

This project can be developed in a basic manner with Visual Studio Code and the C/C++ Extension Pack.
Alternatively, a more specialist compiler such as CLion can be used, with better debugging features.

2. Configure

First run the base configure script, and accept the default NGINX version:

./configure

Select these options to enable Perl tests to run and to enable debugging of the C code in CLion:

DYNAMIC_MODULE=n
NGINX_DEBUG=y

3. Make

Whenever the code in the module changes, run this command to rebuild NGINX:

make

4. Make Install

Pre-creating the nginx folder for development is recommended.
This enables nginx to be run as your own user account, which works better later when debugging:

sudo mkdir /usr/local/nginx
sudo chown yourusername /usr/local/nginx

Whenever you want to update the local system after building code, do a make install.
This deploys an entire NGINX system under the /usr/local/nginx folder:

make install

5. Run NGINX Locally

Finally deploy the nginx.conf development configuration and start NGINX locally:

cp ./resources/localhost/nginx.conf /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/sbin/nginx

6. Act as a Client

You can run curl requests against the nginx system in the same manner as a web or mobile client:

ACCESS_TOKEN='xxx'
curl -i -X GET http://localhost:8080/api \
-H "Authorization: Bearer $ACCESS_TOKEN"

This will result in a 500 error, since the plugin cannot connect to an introspection endpoint yet:

{
    "code": "server_error",
    "message": "Problem encountered processing the request"
}

7. Run the Curity Identity Server

Run a local instance in Docker using the following command.
Then login to http://localhost:6749/admin with credentials admin / Password1.
Then complete the initial setup wizard and accept all defaults:

docker run -it -e PASSWORD=Password1 -p 6749:6749 -p 8443:8443 curity.azurecr.io/curity/idsvr

Then save this XML to a clients.xml file, and upload / merge it via the Changes / Upload option:

<config>
  <profiles xmlns="https://curity.se/ns/conf/base">
    <profile>
      <id>token-service</id>
      <type xmlns:as="https://curity.se/ns/conf/profile/oauth">as:oauth-service</type>
      <expose-detailed-error-messages/>
      <settings>
        <authorization-server xmlns="https://curity.se/ns/conf/profile/oauth">
          <client-store>
            <config-backed>
              <client>
                <id>test-client</id>
                <secret>secret1</secret>
                <capabilities>
                  <client-credentials/>
                </capabilities>
              </client>
              <client>
                <id>test-nginx</id>
                <secret>secret2</secret>
                <capabilities>
                  <introspection/>
                </capabilities>
              </client>
            </config-backed>
          </client-store>
        </authorization-server>
      </settings>
    </profile>
  </profiles>
</config>

8. Test the Plugin Locally

Next run this command to get an opaque access token:

OPAQUE_ACCESS_TOKEN=$(curl -s -X POST http://localhost:8443/oauth/v2/oauth-token \
    -H "Content-Type: application/x-www-form-urlencoded" \
    -d "client_id=test-client" \
    -d "client_secret=secret1" \
    -d "grant_type=client_credentials" | jq -r .access_token)
echo $OPAQUE_ACCESS_TOKEN

Send the opaque token to the stub API with this command, which will result in the plugin introspecting it:

curl -s -X GET 'http://localhost:8080/api' -H "Authorization: Bearer $OPAQUE_ACCESS_TOKEN"

The introspection request made from nginx can, if required, be executed locally, for debugging purposes:

JWT_ACCESS_TOKEN=$(curl -s -X POST http://localhost:8443/oauth/v2/oauth-introspect \
    -H "Accept: application/jwt" \
    -d "client_id=test-nginx" \
    -d "client_secret=secret2" \
    -d "token=$OPAQUE_ACCESS_TOKEN")
echo $JWT_ACCESS_TOKEN

The stub API simply echoes back the JWT access token:

{
    "message": "API was called successfully with eyJraWQiOiI5MTc5OTY5NTAiLCJ4NXQiOiJqeU1UMUgwb3B6MWdYWTZPY3JsaUg0dTU0amciLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiJjNWNjN2M5NS02MjczLTQwYjAtYThkNy0zNzZjZjA5ZTU0MWIiLCJkZWxlZ2F0aW9uSWQiOiIwOTNjYTZiYi1hYTkyLTRhZTMtOTY5NS04MGI2NzE5M2M5ZjAiLCJleHAiOjE2Njc0MTkwMjIsIm5iZiI6MTY2NzQxODcyMiwic2NvcGUiOiIiLCJpc3MiOiJodHRwOi8vMTQ3ZTRiNjhiMmQ0Ojg0NDMvb2F1dGgvdjIvb2F1dGgtYW5vbnltb3VzIiwic3ViIjoidGVzdC1jbGllbnQiLCJhdWQiOiJ0ZXN0LWNsaWVudCIsImlhdCI6MTY2NzQxODcyMiwicHVycG9zZSI6ImFjY2Vzc190b2tlbiJ9.j5qS61HbBuyT-igAhuSxjvYVQc4PWEX5fO5ugOTdaE5Y41oZ8HrywzaTYY-cj-bOZoXsKEbtMXftc-jW5qehiBZd0fvebICpEMUrZ81pVhwoPFmZb3tO5gBaGbzsV1M_s8s_N0n9rd26X3fMmiiIDkwBIdwZhd1fb2LeXtpglYOPlV-nBSCjXsIK5nrlpbbQkTv0NIUQx4ZZG4R9dckkzhYimxT7lwOYDwJIH-GSoPUiCT9N0l8BZiSQ6kl-JP2QcxRisiEfglkZfsmxhMZl3vQIM2HaVsJbuf6A3mKcnkvSiDAA90fGQIL3WnEAjlSaE-EkswMfzOHS4pHnUx1SWQ"
}

9. Debug Code

To perform printf debugging you can add ngx_log_error statements to the C code and then look at NGINX output.
Once nginx is running, select Run / Attach to Process in CLion, then choose the nginx worker process.
Then set breakpoints, after which you can step through code to check variable state carefully.

Clone this wiki locally