-
Notifications
You must be signed in to change notification settings - Fork 16
1. Development
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.
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.
First run the base configure script, and accept the default NGINX version, which defaults to that of the latest NGINX Plus release (1.25.5). If you prefer, enter an nginx open source version instead:
./configure
Select the following options when getting started. The first enables debugging of the C code, while the second enables Perl tests to run:
Do you want to enable debug featured? --> Yes
Do you want to create a dynamic module? --> No
The configure script will download the NGINX source code if it is not already local. If it is, the location may be provided when prompted. By default, version 1.25.5 will be downloaded; a different version can be fetched by setting NGINX_VERSION
before running the configure
script. Any additional parameters (e.g., --prefix
) that NGINX's configure
script supports can also be provided. When this module's configure
script is run, it will pass along --with-compat
to NGINX's script. It asks if a dynamic module should be created (thus passing along --add-dynamic-module
) or if the module should be compiled into the NGINX binary (thus passing --add-module
); by default, it created a dynamically-linked module. It will also ask if debug flags should be enabled; if so, --with-debug
and certain GCC flags will be passed on to NGINX's configure
script to make debugging easier.
WARNING If --without-pcre
, --without-http_gzip_module
and potentially other flags are provided to the configure
script and a module is created, it will not be compatible with NGINX Plus or the pre-compiled open source NGINX binaries; if you include such flags (when building the module), you will only be able to load it into a custom build of NGINX that also excludes the same functionality. If the configure
script exits with an error about a missing dependency, like PCRE and zlib, install those instead of excluding them if compatibility with pre-build NGINX binaries is desired.
The code can be imported into CLion 2020.2 or newer as a Makefile project. To do this though, you need to run the configure
script without running make
or make all
. Also, CLion will not work if the clean target it set since this target deletes the Makefile, which is generated by the configure
script. If this process is followed, the project will import easily and all the smart IDE features will work.
Whenever the code in the module changes, run this command to rebuild NGINX, which will delegate to NGINX's Makefile:
make
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
Finally deploy the nginx.conf
development configuration and start NGINX locally:
cp ./testing/localhost/nginx.conf /usr/local/nginx/conf/nginx.conf
/usr/local/nginx/sbin/nginx
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"
}
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>
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"
}
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.
You can consult the following sources of information for further details on NGINX module development: