├── autogen.sh ├── src ├── handle │ ├── .gitignore │ ├── request_uri.c │ ├── jwks.c │ ├── revoke.c │ ├── dpop.c │ ├── content.c │ └── handle.h ├── proto │ ├── .gitignore │ ├── pkce.c │ ├── proto.c │ ├── dpop.c │ ├── profile.c │ ├── discovery.c │ └── jwks.c ├── util │ ├── .gitignore │ ├── pcre_subst.h │ ├── base64.c │ ├── random.c │ ├── key.c │ ├── jq.c │ ├── expr.c │ └── file.c ├── cfg │ ├── .gitignore │ ├── cache.h │ ├── parse.h │ ├── oauth.h │ └── dir.h ├── cache │ ├── .gitignore │ └── redis.h ├── .gitignore ├── oauth.h ├── state.h ├── metadata.h ├── Makefile.am ├── const.h ├── session.h └── mod_auth_openidc.h ├── m4 └── .gitignore ├── .clang-format ├── .github ├── ISSUE_TEMPLATE │ └── config.yml └── workflows │ ├── issues.yml │ ├── build.yml │ ├── codeql-analysis.yml │ ├── sonarqube.yml.save │ └── coverity.yml ├── test ├── .gitignore ├── ecpriv.key ├── public.pem ├── post_preserve.template ├── eccert.pem ├── certificate.pem ├── post_restore.template ├── private.pem ├── Makefile.am ├── check_util.c ├── util.h ├── check_util.h └── util.c ├── Makefile.am ├── sonar-project.properties ├── .gitignore ├── SECURITY.md ├── INSTALL ├── AUTHORS ├── configure.ac └── README.md /autogen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | autoreconf --force --install 3 | rm -rf autom4te.cache/ 4 | -------------------------------------------------------------------------------- /src/handle/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps/ 2 | /.libs/ 3 | /.dirstamp 4 | /*.lo 5 | /*.o 6 | /*.gcno 7 | -------------------------------------------------------------------------------- /src/proto/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps/ 2 | /.libs/ 3 | /*.lo 4 | /*.o 5 | /.dirstamp 6 | /*.gcno 7 | -------------------------------------------------------------------------------- /src/util/.gitignore: -------------------------------------------------------------------------------- 1 | /.deps/ 2 | /.libs/ 3 | /*.lo 4 | /*.o 5 | /.dirstamp 6 | /*.gcno 7 | -------------------------------------------------------------------------------- /m4/.gitignore: -------------------------------------------------------------------------------- 1 | /libtool.m4 2 | /ltoptions.m4 3 | /ltsugar.m4 4 | /ltversion.m4 5 | /lt~obsolete.m4 6 | -------------------------------------------------------------------------------- /src/cfg/.gitignore: -------------------------------------------------------------------------------- 1 | /cmds.inc 2 | /.deps/ 3 | /.dirstamp 4 | /.libs/ 5 | /*.lo 6 | /*.o 7 | /*.gcno 8 | -------------------------------------------------------------------------------- /src/cache/.gitignore: -------------------------------------------------------------------------------- 1 | /*.lo 2 | /*.o 3 | /*.slo 4 | /.libs 5 | /.deps/ 6 | /.dirstamp 7 | /*.gcno 8 | /hiredis-* 9 | -------------------------------------------------------------------------------- /src/.gitignore: -------------------------------------------------------------------------------- 1 | /*.lo 2 | /*.o 3 | /*.slo 4 | /*.la 5 | /.libs 6 | /.deps/ 7 | /.dirstamp 8 | /*.gcno 9 | /config.h 10 | /config.h.in 11 | /config.h.in~ 12 | /stamp-h1 13 | /Makefile 14 | /Makefile.in 15 | -------------------------------------------------------------------------------- /.clang-format: -------------------------------------------------------------------------------- 1 | BasedOnStyle: LLVM 2 | ColumnLimit: 120 3 | IndentWidth: 8 4 | UseTab: Always 5 | BreakBeforeBraces: Attach 6 | AllowShortIfStatementsOnASingleLine: false 7 | IndentCaseLabels: false 8 | AllowShortFunctionsOnASingleLine: None 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/config.yml: -------------------------------------------------------------------------------- 1 | blank_issues_enabled: false 2 | contact_links: 3 | - name: Questions and Suggestions 4 | url: https://github.com/OpenIDC/mod_auth_openidc/discussions 5 | about: This issue tracker is not for end users, please provide your question/suggestion in the Discussions forum here. 6 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | /*.la 2 | /*.lo 3 | /*.o 4 | /*.slo 5 | /.libs/ 6 | /.deps/ 7 | /*.log 8 | /*.trs 9 | /.dirstamp 10 | /*.gcno 11 | /*.gcda 12 | /Makefile 13 | /Makefile.in 14 | /test 15 | /test-cmd 16 | /test_jose 17 | /test_util 18 | /Makefile 19 | /Makefile.in 20 | /test_cfg 21 | /test_http 22 | /test_cache 23 | /test_proto 24 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | ACLOCAL_AMFLAGS=-I m4 2 | 3 | SUBDIRS = src test 4 | 5 | EXTRA_DIST = \ 6 | README.md \ 7 | ChangeLog \ 8 | INSTALL \ 9 | AUTHORS \ 10 | LICENSE.txt \ 11 | auth_openidc.conf 12 | 13 | clang-format: 14 | clang-format -style=file -i $$(find . -maxdepth 3 -name \*\.[ch]) 15 | 16 | valgrind check-code-coverage: check 17 | ${MAKE} -C test $@ 18 | -------------------------------------------------------------------------------- /test/ecpriv.key: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIHuAgEAMBAGByqGSM49AgEGBSuBBAAjBIHWMIHTAgEBBEIAoXDJYBnYWJNMSh9d 3 | c4LojYYE9B4TIKexXOjTvmEI5x5tiAunNKPzFZ+ROrGxSrwUXlzGUpLePKbeqCy5 4 | XQRvTB2hgYkDgYYABAEehIfVYXSxAPq5uVkdP09C4ysrCbgZEqF2kfBo6YR76Dk6 5 | 5Y3AAkbFZUxEvRTJG8WzRLOCXcT4DyZfRvnvVhCU3gGppoH5WWibkncnCv3HFF5E 6 | l4zUHfDbKibr/SxaZOWLNTgIoq1purpLVxvACzUsUn33LqwavM6mcmdeNXVeqksy 7 | kA== 8 | -----END PRIVATE KEY----- 9 | -------------------------------------------------------------------------------- /sonar-project.properties: -------------------------------------------------------------------------------- 1 | sonar.projectKey=OpenIDC_mod_auth_openidc 2 | sonar.organization=openidc 3 | 4 | # This is the name and version displayed in the SonarCloud UI. 5 | #sonar.projectName=mod_auth_openidc 6 | #sonar.projectVersion=1.0 7 | 8 | # Path is relative to the sonar-project.properties file. Replace "\" by "/" on Windows. 9 | #sonar.sources=. 10 | 11 | # Encoding of the source code. Default is default system encoding 12 | #sonar.sourceEncoding=UTF-8 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /autom4te.cache/ 2 | /.vscode/ 3 | /.libs/ 4 | /.settings/ 5 | /.project 6 | /.cproject 7 | /.dockerignore 8 | /aclocal.m4 9 | /ar-lib 10 | /compile 11 | /config.guess 12 | /config.guess~ 13 | /config.log 14 | /config.status 15 | /config.sub 16 | /config.sub~ 17 | /configure 18 | /configure~ 19 | /depcomp 20 | /*.rpm 21 | /install-sh 22 | /install-sh~ 23 | /*.la 24 | /libtool 25 | /ltmain.sh 26 | /Makefile 27 | /Makefile.in 28 | /missing 29 | /test-driver 30 | -------------------------------------------------------------------------------- /test/public.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAiGeTXbfV5bMppx7o7qML 3 | CuVIKqbBa/qOzBiNNpe0K8rjg7+1z9GCuSlqbZtM0/5BQ6bGonnSPD++PowhFdiv 4 | S4WNA33O0Kl1tQ0wdH3TOnwueIO9ahfW4q0BGFvMObneK+tjwiNMj1l+cZt8pvuS 5 | +3LtTWIzC+hTZM4caUmy5olm5PVdmru6C6V5rxkbYBPITFSzl5mpuo/C6RV/MYRw 6 | Ah60ghs2OEvIWDrJkZnYaF7sjHC9j+4kfcM5oY7Zhg8KuHyloudYNzlqjVAPd0Mb 7 | kLkh1pa8fmHsnN6cgfXYtFK7Z8WjYDUAhTH1JjZCVSFN55A+51dgD4cQNzieLEEk 8 | JwIDAQAB 9 | -----END PUBLIC KEY----- 10 | -------------------------------------------------------------------------------- /test/post_preserve.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Preserving... 6 | 12 | 13 | 14 |

Preserving...

15 | 16 | 17 | -------------------------------------------------------------------------------- /.github/workflows/issues.yml: -------------------------------------------------------------------------------- 1 | on: 2 | issues: 3 | types: [opened, reopened] 4 | jobs: 5 | check: 6 | if: github.event.issue.user.login != 'zandbelt' 7 | runs-on: ubuntu-latest 8 | steps: 9 | - if: github.event.action == 'opened' 10 | uses: actions-ecosystem/action-add-labels@v1 11 | name: Label Invalid 12 | with: 13 | labels: invalid 14 | - uses: peter-evans/close-issue@v2 15 | name: Close Issue 16 | with: 17 | comment: "https://github.com/OpenIDC/mod_auth_openidc/wiki#20-why-is-my-ticket-closed-as-invalid" 18 | 19 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v4 10 | - name: Dependencies 11 | run: | 12 | sudo apt-get update -y 13 | sudo apt-get install -y apache2-dev libcjose-dev libssl-dev check pkg-config 14 | sudo apt-get install -y libjansson-dev libcurl4-openssl-dev libhiredis-dev libpcre2-dev libjq-dev check 15 | sudo apt-get install -y valgrind 16 | - name: Configure 17 | run: | 18 | ./autogen.sh 19 | ./configure --with-jq 20 | - name: Make 21 | run: make 22 | - name: Test 23 | run: make check || (cat test/test-suite.log && exit -1) 24 | - name: Valgrind 25 | run: make valgrind 26 | - name: Distcheck 27 | run: make distcheck DESTDIR=/tmp/mod_auth_openidc 28 | -------------------------------------------------------------------------------- /test/eccert.pem: -------------------------------------------------------------------------------- 1 | openssl req -x509 -newkey EC:<(openssl ecparam -name secp521r1) -keyout ecpriv.key -out eccert.pem -days 3650 -nodes -subj '/CN=localhost' 2 | -----BEGIN CERTIFICATE----- 3 | MIICBDCCAWagAwIBAgIUdYpkXaCal7IwjHix3n1PP9/O6OcwCgYIKoZIzj0EAwIw 4 | FDESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTIzMDMyMzIwNDU1MFoXDTMzMDMyMDIw 5 | NDU1MFowFDESMBAGA1UEAwwJbG9jYWxob3N0MIGbMBAGByqGSM49AgEGBSuBBAAj 6 | A4GGAAQBHoSH1WF0sQD6ublZHT9PQuMrKwm4GRKhdpHwaOmEe+g5OuWNwAJGxWVM 7 | RL0UyRvFs0Szgl3E+A8mX0b571YQlN4BqaaB+Vlom5J3Jwr9xxReRJeM1B3w2yom 8 | 6/0sWmTlizU4CKKtabq6S1cbwAs1LFJ99y6sGrzOpnJnXjV1XqpLMpCjUzBRMB0G 9 | A1UdDgQWBBTKfLLXyRVQpnXFf19Bs7eXRPlRmzAfBgNVHSMEGDAWgBTKfLLXyRVQ 10 | pnXFf19Bs7eXRPlRmzAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA4GLADCB 11 | hwJBGkoifMDYwsSLSmnnVdFftqTwxrjdgrtPMRzetz/w/D9KkM4Mlufgv5jBXuWc 12 | EiP9ray2ZgAGhdkvoOfsc8g1l6ICQgEJ+9R5K2WKlDTEydmiHiSYQHSVyS61PFsk 13 | m537AqrLVSRu80Sezu2W4m8IF2UbbRZiUPaHPIx9Xe3GdpqIEmPFfA== 14 | -----END CERTIFICATE----- 15 | -------------------------------------------------------------------------------- /test/certificate.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIICnTCCAYUCBgFuk1+FLDANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAd2aW5j 3 | ZW50MB4XDTE5MTEyMjEzNDcyMVoXDTI5MTEyMjEzNDkwMVowEjEQMA4GA1UEAwwH 4 | dmluY2VudDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAIhnk1231eWz 5 | Kace6O6jCwrlSCqmwWv6jswYjTaXtCvK44O/tc/Rgrkpam2bTNP+QUOmxqJ50jw/ 6 | vj6MIRXYr0uFjQN9ztCpdbUNMHR90zp8LniDvWoX1uKtARhbzDm53ivrY8IjTI9Z 7 | fnGbfKb7kvty7U1iMwvoU2TOHGlJsuaJZuT1XZq7ugulea8ZG2ATyExUs5eZqbqP 8 | wukVfzGEcAIetIIbNjhLyFg6yZGZ2Ghe7IxwvY/uJH3DOaGO2YYPCrh8paLnWDc5 9 | ao1QD3dDG5C5IdaWvH5h7JzenIH12LRSu2fFo2A1AIUx9SY2QlUhTeeQPudXYA+H 10 | EDc4nixBJCcCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEAfAo40il4qw7DfOkke0p1 11 | ZFAgLQQS3J5hYNDSRvVv+vxkk9o/N++zTMoHbfcDcU5BdVH6Qsr/12PXPX7Ur5WY 12 | Dq+bWGAK3MAaGtZlmycFeVhoVRfab4TUWUy43H3VyFUNqjGRAVJ/VD1RW3fJ18Kr 13 | QTN2fcKSd88Jqt5TvjROKghq95+8BQtlhrR/sQVrjgYwc+eU9ljWI56MQXbpHstl 14 | 9IewMXnusSPxKRTbutjaxzKaoXRTUncPL6ga0SSxOTdKksM4ZYpPnq0B93silb+0 15 | qs8aJraGzjAmLE30opfufP+roth19VJxAfYsW5mgAmXP9kEAF+iWB8FB4/Q4noNG 16 | 8Q== 17 | -----END CERTIFICATE----- 18 | -------------------------------------------------------------------------------- /.github/workflows/codeql-analysis.yml: -------------------------------------------------------------------------------- 1 | name: "CodeQL" 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | analyze: 7 | name: Analyze 8 | runs-on: ubuntu-latest 9 | permissions: 10 | actions: read 11 | contents: read 12 | security-events: write 13 | 14 | strategy: 15 | fail-fast: false 16 | matrix: 17 | language: [ 'cpp' ] 18 | # https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed 19 | 20 | steps: 21 | - name: Checkout repository 22 | uses: actions/checkout@v4 23 | 24 | - name: Install packages 25 | run: | 26 | sudo apt-get update 27 | sudo apt-get install -y apache2-dev libcjose-dev libssl-dev 28 | sudo apt-get install -y libjansson-dev libcurl4-openssl-dev libhiredis-dev 29 | 30 | - name: Initialize CodeQL 31 | uses: github/codeql-action/init@v3 32 | with: 33 | languages: ${{ matrix.language }} 34 | 35 | - run: | 36 | ./autogen.sh 37 | ./configure 38 | make check 39 | 40 | - name: Perform CodeQL Analysis 41 | uses: github/codeql-action/analyze@v3 42 | -------------------------------------------------------------------------------- /test/post_restore.template: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Restoring... 6 | 29 | 30 | 31 |

Restoring...

32 |
33 | 34 | 35 | -------------------------------------------------------------------------------- /.github/workflows/sonarqube.yml.save: -------------------------------------------------------------------------------- 1 | name: SonarQube 2 | on: 3 | push: 4 | branches: 5 | - master 6 | pull_request: 7 | types: [opened, synchronize, reopened] 8 | jobs: 9 | build: 10 | name: Build and analyze 11 | runs-on: ubuntu-latest 12 | env: 13 | BUILD_WRAPPER_OUT_DIR: build_wrapper_output_directory # Directory where build-wrapper output will be placed 14 | steps: 15 | - uses: actions/checkout@v4 16 | with: 17 | fetch-depth: 0 # Shallow clones should be disabled for a better relevancy of analysis 18 | - name: Dependencies 19 | run: | 20 | sudo apt-get update -y 21 | sudo apt-get install -y apache2-dev libcjose-dev libssl-dev check pkg-config 22 | sudo apt-get install -y libjansson-dev libcurl4-openssl-dev libhiredis-dev libpcre2-dev libjq-dev check 23 | - name: Install Build Wrapper 24 | uses: SonarSource/sonarqube-scan-action/install-build-wrapper@v5.3.1 25 | - name: Run build-wrapper 26 | run: | 27 | ./autogen.sh 28 | ./configure --with-jq 29 | build-wrapper-linux-x86-64 --out-dir ${{ env.BUILD_WRAPPER_OUT_DIR }} make clean all 30 | - name: Run sonar-scanner 31 | env: 32 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 33 | SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }} 34 | uses: SonarSource/sonarqube-scan-action@v5.3.1 35 | with: 36 | args: > 37 | --define sonar.cfamily.compile-commands=${{ env.BUILD_WRAPPER_OUT_DIR }}/compile_commands.json 38 | -------------------------------------------------------------------------------- /test/private.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEowIBAAKCAQEAiGeTXbfV5bMppx7o7qMLCuVIKqbBa/qOzBiNNpe0K8rjg7+1 3 | z9GCuSlqbZtM0/5BQ6bGonnSPD++PowhFdivS4WNA33O0Kl1tQ0wdH3TOnwueIO9 4 | ahfW4q0BGFvMObneK+tjwiNMj1l+cZt8pvuS+3LtTWIzC+hTZM4caUmy5olm5PVd 5 | mru6C6V5rxkbYBPITFSzl5mpuo/C6RV/MYRwAh60ghs2OEvIWDrJkZnYaF7sjHC9 6 | j+4kfcM5oY7Zhg8KuHyloudYNzlqjVAPd0MbkLkh1pa8fmHsnN6cgfXYtFK7Z8Wj 7 | YDUAhTH1JjZCVSFN55A+51dgD4cQNzieLEEkJwIDAQABAoIBAF3PXfpGREUFQtA8 8 | 4dW9LAsCRO+QX9XzK+IRwIybKL41euNRJakXXeAaK6fV9rCVXC06tcFoJr5o2F4L 9 | 4XU04Nn/r0uHaoT3BozN1VVIc8z1OsCHWe1tF8wtT2OBPqM0wSdTa/hIbo7n7Z4U 10 | YVY2DpAAKlPeBV1bGn9pgQCoPvFs61sdjHlo3y3BO/Q5ki/SMNmq3ilURpSnXSCD 11 | 5x2/jMPRwe2QslUwtb+bKoUD8uqj6PFx3UI7vxGEZSDjJLFPJHG9tEf3s4m/6x7l 12 | cCVZUzZOjLxVCI+Gsl3V9d0MuJEwUYkDO6bpj2sqRBOAqwH01j9AGJxMM/xRpbjq 13 | TGTc6AECgYEA0ENWGZHWN84M1ztxH1DSL+po7MxEdKcwGSqye6379px0ximKr+8+ 14 | DWKS8xeWsBc1OupdrzO2p7lvWwYBstlJoLfVMVEHeLEhkN2fdBjeRzDf2RbbtZnd 15 | NAYHNSX4xv9B8DyJs7js0uVVmOuuojNkoQFqh3NcIFsC7OuGfEhR48ECgYEAp6uo 16 | rIDqGD2YCL+Bx6lEf96Jlcmu5zwB3jnKqSxA5PnkbE4ZS3RidM0HSrUABcq3n4So 17 | 61lwdbGtnjyhBXrEYbpNokVye6RV5DwXZN9LVeA/aZWlAccUHSoDuwovSsowfoG4 18 | xj8yyUUFE8/+xgM0CnqaoWP1tCkrhXk5mX0w4ecCgYEAhp7wOekOOtZjcIFI90As 19 | DbMNjfvgSDOGIM57vvzRATFTPoC92Enip45PhPl7e2oVC3dRhZ389OAl/gWc9XoF 20 | YPFTyuQg20BMfTL1DnvAuu351H81GGdUGHvJDu7zp9Z6Tgsjy9u+ofiCYy39nXVx 21 | F64tqU7Ff1i1RGZecVniLUECgYBdyeyhCb9obdPEWPNMbweNCzsk2VsHp45X8zXE 22 | qadnLc0zNAB8L47/TMyeYl6v3rQV+8vNUgtRGmFGmR1tBj4heGgCtBwUw1j0QRTI 23 | 7Qqj77so4XcaZnR+18iccFcB29WCfieQZTuQUBZF/dvCgXozvl8Ole6Tp0/b6nJo 24 | xBl60wKBgDHdWW2qVche9wuZf6iDyVpE1DouMeg3sUxq77KCUXsmIHUuGgqlhuIj 25 | wLIgkuBOf4dEmSlwB/4onxTx+DRcvK89oZjFUnL9CR8jaE1HQACKj3xMn1ubkXqH 26 | z6itCDUZ0fP+LLYSREyBHlnaYOtXJgxKKK2yC1kTJmBs9HUMaLNk 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Supported Versions 4 | 5 | | Version | Supported | 6 | | ------- | ------------------ | 7 | | 2.4.x | :white_check_mark: | 8 | | < 2.4.0 | :x: | 9 | 10 | ## Reporting a Vulnerability 11 | 12 | Please send an e-mail to support@openidc.com with a description of: 13 | 14 | - a brief description of the vulnerability 15 | - how the vulnerability can be observed 16 | - optionally the type of vulnerability and any related OWASP category 17 | - non-destructive exploitation details 18 | 19 | ## Followup 20 | After submitting your vulnerability report, you will receive an acknowledgement reply usually within 24 working hours of your report being received. 21 | 22 | The team will triage the reported vulnerability, and respond as soon as possible to let you know whether further information is required, whether the vulnerability is in or out of scope, or is a duplicate report. Priority for bug fixes or mitigations is assessed by looking at the impact severity and exploit complexity. 23 | 24 | When the reported vulnerability is resolved, or remediation work is scheduled, the Support team will notify you, and invite you to confirm that the solution covers the vulnerability adequately. 25 | 26 | You are particularly invited to give us feedback on the disclosure handling process, the clarity and quality of the communication relationship, and of course the effectiveness of the vulnerability resolution. This feedback will be used in strict confidence to help us improve our processes for handling reports, developing services, and resolving vulnerabilities. 27 | 28 | Where a report qualifies, we will offer to include you on our thanks and acknowledgement page. We will ask you to confirm the details you want included before they are published. 29 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | Preferably you should use one of the pre-compiled binary packages, available for 2 | various platforms, see: 3 | https://github.com/OpenIDC/mod_auth_openidc/wiki#11-where-can-i-get-binary-packages 4 | and proceed with the Configuration section below. 5 | 6 | If your platform is not supported or you want to run the latest code, 7 | you can build from source as described below. 8 | 9 | Installation from source 10 | ======================== 11 | 12 | You will require development headers and tools for the following 13 | dependencies: 14 | Apache (>=2.0) 15 | cjose (>=0.4.1) 16 | OpenSSL (>=0.9.8) (>=1.0.1 for Elliptic Curve support) 17 | Curl (>=?) 18 | Jansson (>=2.0) (JSON parser for C) 19 | pcre3 (>=?) (Regular Expressions support) 20 | pkg-config 21 | 22 | and if you want Redis support: 23 | hiredis (>=0.9.0) (Redis client for C) 24 | 25 | 26 | Configure, make and install with: 27 | 28 | (run ./autogen.sh first if you work straight from the github source tree) 29 | ./configure --with-apxs=/opt/apache2/bin/apxs2 30 | make 31 | make install 32 | 33 | Note that, depending on your distribution, apxs2 may be named apxs. 34 | 35 | FreeBSD users can use one of the following two options to install mod_auth_openidc: 36 | - To install the port: cd /usr/ports/www/mod_auth_openidc/ && make install clean 37 | - To add the package: pkg install ap24-mod_auth_openidc 38 | 39 | Configuration 40 | ============= 41 | 42 | Edit the configuration file for your web server. Depending on 43 | your distribution, it may be named '/etc/apache/httpd.conf' or something 44 | different. 45 | 46 | You need to add a LoadModule directive for mod_auth_openidc. This will 47 | look similar to this: 48 | 49 | LoadModule auth_openidc_module /usr/lib/apache2/modules/mod_auth_openidc.so 50 | 51 | To find the full path to mod_auth_openidc.so, you may run: 52 | 53 | apxs2 -q LIBEXECDIR 54 | 55 | This will print the path where Apache stores modules. mod_auth_openidc.so 56 | will be stored in that directory. 57 | 58 | After you have added the LoadModule directive, you must add the configuration 59 | for mod_auth_openidc. For a quickstart doing so, see the provided samples 60 | in the README.md file. 61 | 62 | For an exhaustive overview of all configuration primitives, see: auth_openidc.conf 63 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = -I${top_srcdir}/src @APACHE_CFLAGS@ @OPENSSL_CFLAGS@ @CURL_CFLAGS@ @JANSSON_CFLAGS@ @CJOSE_CFLAGS@ @PCRE_CFLAGS@ 2 | AM_CPPFLAGS = @APACHE_CPPFLAGS@ 3 | AM_LDFLAGS = --coverage @APACHE_LDFLAGS@ 4 | LIBADD = $(CODE_COVERAGE_LIBS) @APACHE_LIBS@ @OPENSSL_LIBS@ @CURL_LIBS@ @JANSSON_LIBS@ @CJOSE_LIBS@ @PCRE_LIBS@ 5 | 6 | if HAVE_LIBHIREDIS 7 | AM_CFLAGS += -DUSE_LIBHIREDIS @HIREDIS_CFLAGS@ 8 | LIBADD += @HIREDIS_LIBS@ 9 | endif 10 | 11 | if HAVE_MEMCACHE 12 | AM_CFLAGS += -DUSE_MEMCACHE 13 | endif 14 | 15 | if HAVE_LIBJQ 16 | AM_CFLAGS += -DUSE_LIBJQ @JQ_CFLAGS@ 17 | LIBADD += @JQ_LIBS@ 18 | endif 19 | 20 | if HAVE_LIBBROTLI 21 | AM_CFLAGS += -DUSE_LIBBROTLI @LIBBROTLIENC_CFLAGS@ @LIBBROTLIDEC_CFLAGS@ 22 | LIBADD += @LIBBROTLIENC_LIBS@ @LIBBROTLIDEC_LIBS@ 23 | endif 24 | 25 | if HAVE_LIBZ 26 | AM_CFLAGS += -DUSE_ZLIB @ZLIB_CFLAGS@ 27 | LIBADD += @ZLIB_LIBS@ 28 | endif 29 | 30 | noinst_HEADERS = \ 31 | util.h \ 32 | check_util.h 33 | 34 | LDADD = ${top_builddir}/src/libauth_openidc.la ${LIBADD} 35 | 36 | noinst_PROGRAMS = test-cmd 37 | 38 | TESTS = test 39 | 40 | test_SOURCES = \ 41 | test.c \ 42 | util.c \ 43 | stub.c 44 | 45 | test_cmd_SOURCES = \ 46 | test-cmd.c \ 47 | util.c \ 48 | stub.c 49 | 50 | if HAVE_CHECK 51 | 52 | noinst_LTLIBRARIES = libtest.la 53 | 54 | libtest_la_CFLAGS = ${AM_CFLAGS} -fPIC 55 | 56 | libtest_la_SOURCES = \ 57 | util.c \ 58 | check_util.c \ 59 | stub.c 60 | 61 | AM_CFLAGS += @CHECK_CFLAGS@ 62 | LDADD += libtest.la @CHECK_LIBS@ 63 | 64 | TESTS += \ 65 | test_cfg \ 66 | test_util \ 67 | test_jose \ 68 | test_http \ 69 | test_cache \ 70 | test_proto 71 | 72 | endif 73 | 74 | check_PROGRAMS = $(TESTS) 75 | 76 | EXTRA_DIST = \ 77 | ecpriv.key \ 78 | eccert.pem \ 79 | private.pem \ 80 | public.pem \ 81 | certificate.pem \ 82 | open-redirect-payload-list.txt \ 83 | post_preserve.template \ 84 | post_restore.template 85 | 86 | clean-local: 87 | rm -f *.gcno 88 | 89 | ${TESTS:%=%.valgrind}: ${TESTS} 90 | CK_FORK=no valgrind --error-exitcode=1 --leak-check=full --show-leak-kinds=definite --read-inline-info=yes --keep-debuginfo=yes ./$$(basename $@ .valgrind) 91 | 92 | valgrind: ${TESTS:%=%.valgrind} 93 | 94 | CODE_COVERAGE_LCOV_SHOPTS = --ignore-errors inconsistent --ignore-errors unused 95 | 96 | @CODE_COVERAGE_RULES@ 97 | -------------------------------------------------------------------------------- /src/util/pcre_subst.h: -------------------------------------------------------------------------------- 1 | /************************************************* 2 | * PCRE string replacement * 3 | *************************************************/ 4 | 5 | /* 6 | PCRE is a library of functions to support regular expressions whose syntax 7 | and semantics are as close as possible to those of the Perl 5 language. 8 | pcre_subst is a wrapper around pcre_exec designed to make it easier to 9 | perform PERL style replacements with PCRE. 10 | 11 | Written by: Bert Driehuis 12 | 13 | Copyright (c) 2000 Bert Driehuis 14 | 15 | ----------------------------------------------------------------------------- 16 | Permission is granted to anyone to use this software for any purpose on any 17 | computer system, and to redistribute it freely, subject to the following 18 | restrictions: 19 | 20 | 1. This software is distributed in the hope that it will be useful, 21 | but WITHOUT ANY WARRANTY; without even the implied warranty of 22 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 23 | 24 | 2. The origin of this software must not be misrepresented, either by 25 | explicit claim or by omission. 26 | 27 | 3. Altered versions must be plainly marked as such, and must not be 28 | misrepresented as being the original software. 29 | 30 | 4. If PCRE is embedded in any software that is released under the GNU 31 | General Purpose Licence (GPL), then the terms of that licence shall 32 | supersede any condition above with which it is incompatible. 33 | */ 34 | 35 | #ifndef _MOD_AUTH_OPENIDC_PCRE_SUBST_H_ 36 | #define _MOD_AUTH_OPENIDC_PCRE_SUBST_H_ 37 | 38 | #include "const.h" 39 | 40 | #include 41 | #include 42 | 43 | #define OIDC_PCRE_MAXCAPTURE 255 44 | #define OIDC_UTIL_REGEXP_MATCH_SIZE 30 45 | #define OIDC_UTIL_REGEXP_MATCH_NR 1 46 | 47 | struct oidc_pcre; 48 | 49 | struct oidc_pcre *oidc_pcre_compile(apr_pool_t *pool, const char *regexp, char **error_str); 50 | char *oidc_pcre_subst(apr_pool_t *pool, const struct oidc_pcre *, const char *, int, const char *); 51 | int oidc_pcre_exec(apr_pool_t *, struct oidc_pcre *, const char *, int, char **); 52 | void oidc_pcre_free(struct oidc_pcre *); 53 | void oidc_pcre_free_match(struct oidc_pcre *); 54 | int oidc_pcre_get_substring(apr_pool_t *pool, const struct oidc_pcre *, const char *input, int rc, char **sub_str, 55 | char **error_str); 56 | 57 | #endif /* _MOD_AUTH_OPENIDC_PCRE_SUBST_H_ */ 58 | -------------------------------------------------------------------------------- /src/oauth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_OAUTH_H_ 44 | #define _MOD_AUTH_OPENIDC_OAUTH_H_ 45 | 46 | #include "cfg/cfg.h" 47 | 48 | int oidc_oauth_check_userid(request_rec *r, oidc_cfg_t *c, const char *access_token); 49 | apr_byte_t oidc_oauth_get_bearer_token(request_rec *r, const char **access_token); 50 | 51 | #endif /* _MOD_AUTH_OPENIDC_OAUTH_H_ */ 52 | -------------------------------------------------------------------------------- /test/check_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | * 42 | **************************************************************************/ 43 | 44 | #include "check_util.h" 45 | #include 46 | 47 | int oidc_test_suite_run(Suite *s) { 48 | int n_failed = 0; 49 | 50 | SRunner *sr = srunner_create(s); 51 | srunner_run_all(sr, CK_VERBOSE); 52 | n_failed = srunner_ntests_failed(sr); 53 | srunner_free(sr); 54 | 55 | return (n_failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE; 56 | } 57 | -------------------------------------------------------------------------------- /src/state.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_STATE_H_ 44 | #define _MOD_AUTH_OPENIDC_STATE_H_ 45 | 46 | #include "cfg/cfg.h" 47 | 48 | char *oidc_state_cookie_name(request_rec *r, const char *state); 49 | char *oidc_state_browser_fingerprint(request_rec *r, oidc_cfg_t *c, const char *nonce); 50 | int oidc_state_cookies_clean_expired(request_rec *r, oidc_cfg_t *c, const char *currentCookieName, int delete_oldest); 51 | 52 | #endif /* _MOD_AUTH_OPENIDC_STATE_H_ */ 53 | -------------------------------------------------------------------------------- /.github/workflows/coverity.yml: -------------------------------------------------------------------------------- 1 | name: Coverity 2 | 3 | on: 4 | schedule: 5 | - cron: '0 18 * * SUN' 6 | workflow_dispatch: 7 | 8 | #on: 9 | # push: 10 | # branches: [ master, coverity ] 11 | # pull_request: 12 | # types: [opened, synchronize, reopened] 13 | 14 | jobs: 15 | build: 16 | name: Build and analyze 17 | runs-on: ubuntu-latest 18 | if: github.repository == 'OpenIDC/mod_auth_openidc' 19 | steps: 20 | - uses: actions/checkout@v4 21 | with: 22 | fetch-depth: 0 23 | - name: Dependencies 24 | run: | 25 | sudo apt-get update -y 26 | sudo apt-get install -y apache2-dev libcjose-dev libssl-dev check pkg-config 27 | sudo apt-get install -y libjansson-dev libcurl4-openssl-dev libhiredis-dev libpcre2-dev libjq-dev check 28 | - name: Download Coverity Build Tool 29 | env: 30 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 31 | run: | 32 | wget -q https://scan.coverity.com/download/cxx/linux64 --post-data "token=$TOKEN&project=OpenIDC%2Fmod_auth_openidc" -O cov-analysis-linux64.tar.gz 33 | mkdir cov-analysis-linux64 34 | tar xzf cov-analysis-linux64.tar.gz --strip 1 -C cov-analysis-linux64 35 | - name: Configure 36 | run: | 37 | ./autogen.sh 38 | ./configure --with-jq 39 | - name: Make with cov-build 40 | run: | 41 | pwd 42 | export PATH=`pwd`/cov-analysis-linux64/bin:$PATH 43 | cov-build --dir cov-int make check 44 | - name: Submit to Coverity Scan 45 | env: 46 | TOKEN: ${{ secrets.COVERITY_SCAN_TOKEN }} 47 | run: | 48 | tar czvf mod_auth_openidc.tgz cov-int 49 | curl \ 50 | --form project=OpenIDC%2Fmod_auth_openidc \ 51 | --form token=$TOKEN \ 52 | --form email=hans.zandbelt@zmartzone.eu \ 53 | --form file=@mod_auth_openidc.tgz \ 54 | --form version=master \ 55 | --form description="`git rev-parse --abbrev-ref HEAD` `git rev-parse --short HEAD`" \ 56 | https://scan.coverity.com/builds?project=OpenIDC%2Fmod_auth_openidc 57 | # - name: Coverity Scan 58 | # uses: blackduck-inc/black-duck-security-scan@v2.0.0 59 | # with: 60 | # coverity_url: ${{ vars.COVERITY_URL }} 61 | # coverity_project_name: ${{ vars.COVERITY_PROJECT_NAME }} 62 | # coverity_user: ${{ vars.COVERITY_USER }} 63 | # coverity_passphrase: ${{ secrets.COVERITY_PASSPHRASE }} 64 | # coverity_build_command: make all 65 | # coverity_clean_command: make clean 66 | -------------------------------------------------------------------------------- /test/util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_TEST_UTIL_H_ 44 | #define _MOD_AUTH_OPENIDC_TEST_UTIL_H_ 45 | 46 | #include "const.h" // for the PACKAGE_* defines 47 | #include 48 | #include 49 | #include 50 | #include 51 | 52 | #include "cfg/cfg.h" 53 | 54 | void oidc_test_setup(void); 55 | void oidc_test_teardown(void); 56 | apr_pool_t *oidc_test_pool_get(void); 57 | request_rec *oidc_test_request_get(void); 58 | oidc_cfg_t *oidc_test_cfg_get(void); 59 | cmd_parms *oidc_test_cmd_get(const char *primitive); 60 | 61 | #endif // _MOD_AUTH_OPENIDC_TEST_UTIL_H_ 62 | -------------------------------------------------------------------------------- /src/handle/request_uri.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "handle/handle.h" 44 | #include "metadata.h" 45 | #include "mod_auth_openidc.h" 46 | #include "proto/proto.h" 47 | #include "util/util.h" 48 | 49 | /* 50 | * handle request object by reference request 51 | */ 52 | int oidc_request_uri(request_rec *r, oidc_cfg_t *c) { 53 | 54 | char *request_ref = NULL; 55 | oidc_util_url_parameter_get(r, OIDC_REDIRECT_URI_REQUEST_REQUEST_URI, &request_ref); 56 | if (request_ref == NULL) { 57 | oidc_error(r, "no \"%s\" parameter found", OIDC_REDIRECT_URI_REQUEST_REQUEST_URI); 58 | return HTTP_BAD_REQUEST; 59 | } 60 | 61 | char *jwt = NULL; 62 | oidc_cache_get_request_uri(r, request_ref, &jwt); 63 | if (jwt == NULL) { 64 | oidc_error(r, "no cached JWT found for %s reference: %s", OIDC_REDIRECT_URI_REQUEST_REQUEST_URI, 65 | request_ref); 66 | return HTTP_NOT_FOUND; 67 | } 68 | 69 | oidc_cache_set_request_uri(r, request_ref, NULL, 0); 70 | 71 | return oidc_util_http_content_prep(r, jwt, _oidc_strlen(jwt), OIDC_HTTP_CONTENT_TYPE_JWT); 72 | } 73 | -------------------------------------------------------------------------------- /src/handle/jwks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "handle/handle.h" 44 | 45 | /* 46 | * handle request for JWKs 47 | */ 48 | int oidc_jwks_request(request_rec *r, oidc_cfg_t *c) { 49 | /* pickup requested JWKs type */ 50 | // char *jwks_type = NULL; 51 | // oidc_util_get_request_parameter(r, OIDC_REDIRECT_URI_REQUEST_JWKS, &jwks_type); 52 | char *jwks = apr_pstrdup(r->pool, "{ \"keys\" : ["); 53 | int i = 0; 54 | apr_byte_t first = TRUE; 55 | const oidc_jwk_t *jwk = NULL; 56 | oidc_jose_error_t err; 57 | char *s_json = NULL; 58 | 59 | /* loop over the RSA/EC public keys */ 60 | for (i = 0; oidc_cfg_public_keys_get(c) && i < oidc_cfg_public_keys_get(c)->nelts; i++) { 61 | jwk = APR_ARRAY_IDX(oidc_cfg_public_keys_get(c), i, oidc_jwk_t *); 62 | 63 | if (oidc_jwk_to_json(r->pool, jwk, &s_json, &err) == TRUE) { 64 | jwks = apr_psprintf(r->pool, "%s%s %s ", jwks, first ? "" : ",", s_json); 65 | first = FALSE; 66 | } else { 67 | oidc_error(r, "could not convert RSA/EC JWK to JSON using oidc_jwk_to_json: %s", 68 | oidc_jose_e2s(r->pool, err)); 69 | } 70 | } 71 | 72 | // TODO: send stuff if first == FALSE? 73 | jwks = apr_psprintf(r->pool, "%s ] }", jwks); 74 | 75 | return oidc_util_http_send(r, jwks, _oidc_strlen(jwks), OIDC_HTTP_CONTENT_TYPE_JSON, OK); 76 | } 77 | -------------------------------------------------------------------------------- /src/metadata.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_METADATA_H_ 44 | #define _MOD_AUTH_OPENIDC_METADATA_H_ 45 | 46 | #include "cfg/cfg.h" 47 | #include "cfg/provider.h" 48 | 49 | apr_byte_t oidc_metadata_provider_get(request_rec *r, oidc_cfg_t *cfg, const char *issuer, json_t **j_provider, 50 | apr_byte_t allow_discovery); 51 | apr_byte_t oidc_metadata_provider_retrieve(request_rec *r, oidc_cfg_t *cfg, const char *issuer, const char *url, 52 | json_t **j_metadata, char **response); 53 | apr_byte_t oidc_metadata_provider_parse(request_rec *r, oidc_cfg_t *cfg, json_t *j_provider, oidc_provider_t *provider); 54 | apr_byte_t oidc_metadata_provider_is_valid(request_rec *r, oidc_cfg_t *cfg, json_t *j_provider, const char *issuer); 55 | apr_byte_t oidc_metadata_list(request_rec *r, oidc_cfg_t *cfg, apr_array_header_t **arr); 56 | apr_byte_t oidc_metadata_get(request_rec *r, oidc_cfg_t *cfg, const char *selected, oidc_provider_t **provider, 57 | apr_byte_t allow_discovery); 58 | apr_byte_t oidc_metadata_jwks_get(request_rec *r, oidc_cfg_t *cfg, const oidc_jwks_uri_t *jwks_uri, 59 | int ssl_validate_server, json_t **j_jwks, apr_byte_t *refresh); 60 | apr_byte_t oidc_oauth_metadata_provider_parse(request_rec *r, oidc_cfg_t *c, json_t *j_provider); 61 | 62 | #endif /* _MOD_AUTH_OPENIDC_METADATA_H_ */ 63 | -------------------------------------------------------------------------------- /src/handle/revoke.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "handle/handle.h" 44 | #include "mod_auth_openidc.h" 45 | 46 | int oidc_revoke_session(request_rec *r, oidc_cfg_t *c) { 47 | apr_byte_t rc = FALSE; 48 | char *session_id = NULL; 49 | 50 | oidc_util_url_parameter_get(r, OIDC_REDIRECT_URI_REQUEST_REVOKE_SESSION, &session_id); 51 | if (session_id == NULL) 52 | return HTTP_BAD_REQUEST; 53 | 54 | if (oidc_cfg_session_type_get(c) == OIDC_SESSION_TYPE_SERVER_CACHE) 55 | rc = oidc_cache_set_session(r, session_id, NULL, 0); 56 | else 57 | oidc_warn(r, "cannot revoke session because server side caching is not in use"); 58 | 59 | r->user = ""; 60 | 61 | return (rc == TRUE) ? OK : HTTP_INTERNAL_SERVER_ERROR; 62 | } 63 | 64 | /* 65 | * handle a request to invalidate a cached access token introspection result 66 | */ 67 | int oidc_revoke_at_cache_remove(request_rec *r, oidc_cfg_t *c) { 68 | char *access_token = NULL; 69 | oidc_util_url_parameter_get(r, OIDC_REDIRECT_URI_REQUEST_REMOVE_AT_CACHE, &access_token); 70 | 71 | char *cache_entry = NULL; 72 | oidc_cache_get_access_token(r, access_token, &cache_entry); 73 | if (cache_entry == NULL) { 74 | oidc_error(r, "no cached access token found for value: %s", access_token); 75 | return HTTP_NOT_FOUND; 76 | } 77 | 78 | oidc_cache_set_access_token(r, access_token, NULL, 0); 79 | 80 | return OK; 81 | } 82 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CFLAGS = $(CODE_COVERAGE_CFLAGS) -DNAMEVER="@NAMEVER@" @APACHE_CFLAGS@ @OPENSSL_CFLAGS@ @CURL_CFLAGS@ @JANSSON_CFLAGS@ @CJOSE_CFLAGS@ @PCRE_CFLAGS@ 2 | AM_CPPFLAGS = $(CODE_COVERAGE_CPPFLAGS) @APACHE_CPPFLAGS@ 3 | AM_LDFLAGS = --coverage @APACHE_LDFLAGS@ 4 | LIBADD = $(CODE_COVERAGE_LIBS) @APACHE_LIBS@ @OPENSSL_LIBS@ @CURL_LIBS@ @JANSSON_LIBS@ @CJOSE_LIBS@ @PCRE_LIBS@ 5 | 6 | if HAVE_LIBHIREDIS 7 | AM_CFLAGS += -DUSE_LIBHIREDIS @HIREDIS_CFLAGS@ 8 | LIBADD += @HIREDIS_LIBS@ 9 | endif 10 | 11 | if HAVE_MEMCACHE 12 | AM_CFLAGS += -DUSE_MEMCACHE 13 | endif 14 | 15 | if HAVE_LIBJQ 16 | AM_CFLAGS += -DUSE_LIBJQ @JQ_CFLAGS@ 17 | LIBADD += @JQ_LIBS@ 18 | endif 19 | 20 | if HAVE_LIBBROTLI 21 | AM_CFLAGS += -DUSE_LIBBROTLI @LIBBROTLIENC_CFLAGS@ @LIBBROTLIDEC_CFLAGS@ 22 | LIBADD += @LIBBROTLIENC_LIBS@ @LIBBROTLIDEC_LIBS@ 23 | endif 24 | 25 | if HAVE_LIBZ 26 | AM_CFLAGS += -DUSE_ZLIB @ZLIB_CFLAGS@ 27 | LIBADD += @ZLIB_LIBS@ 28 | endif 29 | 30 | noinst_LTLIBRARIES = libauth_openidc.la 31 | 32 | libauth_openidc_la_SOURCES = \ 33 | mod_auth_openidc.c \ 34 | state.c \ 35 | cfg/cfg.c \ 36 | cfg/cache.c \ 37 | cfg/provider.c \ 38 | cfg/oauth.c \ 39 | cfg/dir.c \ 40 | cfg/parse.c \ 41 | cfg/cmds.c \ 42 | cache/file.c \ 43 | cache/shm.c \ 44 | cache/common.c \ 45 | handle/authz.c \ 46 | handle/content.c \ 47 | handle/discovery.c \ 48 | handle/dpop.c \ 49 | handle/info.c \ 50 | handle/jwks.c \ 51 | handle/logout.c \ 52 | handle/refresh.c \ 53 | handle/request_uri.c \ 54 | handle/request.c \ 55 | handle/response.c \ 56 | handle/revoke.c \ 57 | handle/session_management.c \ 58 | handle/userinfo.c \ 59 | proto/auth.c \ 60 | proto/discovery.c \ 61 | proto/dpop.c \ 62 | proto/id_token.c \ 63 | proto/jwks.c \ 64 | proto/jwt.c \ 65 | proto/pkce.c \ 66 | proto/profile.c \ 67 | proto/proto.c \ 68 | proto/request.c \ 69 | proto/response.c \ 70 | proto/state.c \ 71 | proto/token.c \ 72 | proto/userinfo.c \ 73 | util/appinfo.c \ 74 | util/base64.c \ 75 | util/expr.c \ 76 | util/file.c \ 77 | util/html.c \ 78 | util/jq.c \ 79 | util/json.c \ 80 | util/jwt.c \ 81 | util/key.c \ 82 | util/pcre_subst.c \ 83 | util/random.c \ 84 | util/url.c \ 85 | util/util.c \ 86 | metrics.c \ 87 | oauth.c \ 88 | http.c \ 89 | session.c \ 90 | metadata.c \ 91 | jose.c 92 | 93 | if HAVE_LIBHIREDIS 94 | libauth_openidc_la_SOURCES += \ 95 | cache/redis.c 96 | endif 97 | 98 | if HAVE_MEMCACHE 99 | libauth_openidc_la_SOURCES += \ 100 | cache/memcache.c 101 | endif 102 | 103 | noinst_HEADERS = \ 104 | cfg/cfg.h \ 105 | cfg/cfg_int.h \ 106 | cfg/cache.h \ 107 | cfg/provider.h \ 108 | cfg/oauth.h \ 109 | cfg/dir.h \ 110 | cfg/parse.h \ 111 | mod_auth_openidc.h \ 112 | state.h \ 113 | handle/handle.h \ 114 | proto/proto.h \ 115 | cache/cache.h \ 116 | util/util.h \ 117 | util/pcre_subst.h \ 118 | oauth.h \ 119 | metadata.h \ 120 | session.h \ 121 | jose.h \ 122 | http.h \ 123 | metrics.h \ 124 | const.h 125 | 126 | if HAVE_LIBHIREDIS 127 | noinst_HEADERS += \ 128 | cache/redis.h 129 | endif 130 | 131 | noinst_DATA = mod_auth_openidc.la 132 | 133 | mod_auth_openidc.la: libauth_openidc.la 134 | ${APXS} -c -o $@ libauth_openidc.la ${AM_CFLAGS} ${LIBADD} 135 | 136 | install-exec-local: 137 | ${INSTALL} -d $(DESTDIR)@APACHE_MODULEDIR@ 138 | ${INSTALL} -p -m 755 .libs/mod_auth_openidc.so $(DESTDIR)@APACHE_MODULEDIR@/mod_auth_openidc.so 139 | 140 | uninstall-local: 141 | rm -f $(DESTDIR)@APACHE_MODULEDIR@/mod_auth_openidc.so mod_auth_openidc.la 142 | 143 | clean-local: 144 | rm -f mod_auth_openidc.la *.gcno */*.gcno 145 | -------------------------------------------------------------------------------- /test/check_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_TEST_CHECK_UTIL_H_ 44 | #define _MOD_AUTH_OPENIDC_TEST_CHECK_UTIL_H_ 45 | 46 | #include 47 | 48 | #ifndef _ck_assert_ptr_null 49 | #define _ck_assert_ptr_null(X, OP) \ 50 | do { \ 51 | const void *_ck_x = (X); \ 52 | ck_assert_msg(_ck_x OP NULL, "Assertion '%s' failed: %s == %#lx", #X " " #OP " NULL", #X, \ 53 | (unsigned long)(uintptr_t)_ck_x); \ 54 | } while (0) 55 | #define ck_assert_ptr_null(X) _ck_assert_ptr_null(X, ==) 56 | #define ck_assert_ptr_nonnull(X) _ck_assert_ptr_null(X, !=) 57 | #endif 58 | 59 | #ifndef _ck_assert_ptr 60 | #define _ck_assert_ptr(X, OP, Y) \ 61 | do { \ 62 | const void *_ck_x = (X); \ 63 | const void *_ck_y = (Y); \ 64 | ck_assert_msg(_ck_x OP _ck_y, "Assertion '%s' failed: %s == %#lx, %s == %#lx", #X " " #OP " " #Y, #X, \ 65 | (unsigned long)(uintptr_t)_ck_x, #Y, (unsigned long)(uintptr_t)_ck_y); \ 66 | } while (0) 67 | #define ck_assert_ptr_eq(X, Y) _ck_assert_ptr(X, ==, Y) 68 | #endif 69 | 70 | int oidc_test_suite_run(Suite *s); 71 | 72 | #endif // _MOD_AUTH_OPENIDC_TEST_CHECK_UTIL_H_ 73 | -------------------------------------------------------------------------------- /src/cache/redis.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * Copyright (C) 2013-2017 Ping Identity Corporation 23 | * All rights reserved. 24 | * 25 | * DISCLAIMER OF WARRANTIES: 26 | * 27 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 28 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 29 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 30 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 31 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 32 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 33 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 34 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 35 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 36 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 37 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 38 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | * 41 | * caching using a Redis backend 42 | * 43 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 44 | */ 45 | 46 | #ifndef _MOD_AUTH_OPENIDC_REDIS_H_ 47 | #define _MOD_AUTH_OPENIDC_REDIS_H_ 48 | 49 | #include "cfg/cache.h" 50 | #include "hiredis/hiredis.h" 51 | 52 | struct oidc_cache_cfg_redis_t; 53 | 54 | typedef apr_status_t (*oidc_cache_redis_connect_function_t)(request_rec *, struct oidc_cache_cfg_redis_t *); 55 | typedef redisReply *(*oidc_cache_redis_command_function_t)(request_rec *, struct oidc_cache_cfg_redis_t *, char **, 56 | const char *format, va_list ap); 57 | typedef apr_status_t (*oidc_cache_redis_disconnect_function_t)(struct oidc_cache_cfg_redis_t *); 58 | 59 | typedef struct oidc_cache_cfg_redis_t { 60 | oidc_cache_mutex_t *mutex; 61 | char *username; 62 | char *passwd; 63 | int database; 64 | struct timeval connect_timeout; 65 | int keepalive; 66 | struct timeval timeout; 67 | char *host_str; 68 | apr_port_t port; 69 | redisContext *rctx; 70 | oidc_cache_redis_connect_function_t connect; 71 | oidc_cache_redis_command_function_t command; 72 | oidc_cache_redis_disconnect_function_t disconnect; 73 | } oidc_cache_cfg_redis_t; 74 | 75 | int oidc_cache_redis_post_config(apr_pool_t *pool, server_rec *s, oidc_cfg_t *cfg, const char *name); 76 | int oidc_cache_redis_child_init(apr_pool_t *p, server_rec *s); 77 | redisReply *oidc_cache_redis_command(request_rec *r, oidc_cache_cfg_redis_t *context, char **errstr, const char *format, 78 | va_list ap); 79 | apr_byte_t oidc_cache_redis_get(request_rec *r, const char *section, const char *key, char **value); 80 | apr_byte_t oidc_cache_redis_set(request_rec *r, const char *section, const char *key, const char *value, 81 | apr_time_t expiry); 82 | apr_status_t oidc_cache_redis_disconnect(oidc_cache_cfg_redis_t *context); 83 | 84 | apr_byte_t oidc_cache_redis_set_keepalive(request_rec *r, redisContext *rctx, const int keepalive); 85 | apr_byte_t oidc_cache_redis_set_auth(request_rec *r, redisContext *rctx, const char *username, const char *password); 86 | apr_byte_t oidc_cache_redis_set_database(request_rec *r, redisContext *rctx, const int database); 87 | redisContext *oidc_cache_redis_connect_with_timeout(request_rec *r, const char *host, int port, struct timeval ct, 88 | struct timeval t, const char *msg); 89 | 90 | #endif // _MOD_AUTH_OPENIDC_REDIS_H_ 91 | -------------------------------------------------------------------------------- /src/proto/pkce.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "proto/proto.h" 44 | #include "util/util.h" 45 | 46 | static apr_byte_t oidc_proto_pkce_code_verifier_gen(request_rec *r, char **code_verifier) { 47 | return oidc_util_rand_str(r, code_verifier, OIDC_PROTO_CODE_VERIFIER_LENGTH); 48 | } 49 | /* 50 | * PCKE "plain" proto state 51 | */ 52 | static apr_byte_t oidc_proto_pkce_state_plain(request_rec *r, char **state) { 53 | return oidc_proto_pkce_code_verifier_gen(r, state); 54 | } 55 | 56 | /* 57 | * PCKE "plain" code_challenge 58 | */ 59 | static apr_byte_t oidc_proto_pkce_challenge_plain(request_rec *r, const char *state, char **code_challenge) { 60 | *code_challenge = apr_pstrdup(r->pool, state); 61 | return TRUE; 62 | } 63 | 64 | /* 65 | * PCKE "plain" code_verifier 66 | */ 67 | static apr_byte_t oidc_proto_pkce_verifier_plain(request_rec *r, const char *state, char **code_verifier) { 68 | *code_verifier = apr_pstrdup(r->pool, state); 69 | return TRUE; 70 | } 71 | 72 | /* 73 | * PCKE "s256" proto state 74 | */ 75 | static apr_byte_t oidc_proto_pkce_state_s256(request_rec *r, char **state) { 76 | return oidc_proto_pkce_code_verifier_gen(r, state); 77 | } 78 | 79 | /* 80 | * PCKE "s256" code_challenge 81 | */ 82 | static apr_byte_t oidc_proto_pkce_challenge_s256(request_rec *r, const char *state, char **code_challenge) { 83 | if (oidc_util_hash_string_and_base64url_encode(r, OIDC_JOSE_ALG_SHA256, state, code_challenge) == FALSE) { 84 | oidc_error(r, "oidc_util_hash_string_and_base64url_encode returned an error for the code verifier"); 85 | return FALSE; 86 | } 87 | return TRUE; 88 | } 89 | 90 | /* 91 | * PCKE "s256" code_verifier 92 | */ 93 | static apr_byte_t oidc_proto_pkce_verifier_s256(request_rec *r, const char *state, char **code_verifier) { 94 | *code_verifier = apr_pstrdup(r->pool, state); 95 | return TRUE; 96 | } 97 | 98 | /* 99 | * PKCE plain 100 | */ 101 | oidc_proto_pkce_t oidc_pkce_plain = {OIDC_PKCE_METHOD_PLAIN, oidc_proto_pkce_state_plain, 102 | oidc_proto_pkce_verifier_plain, oidc_proto_pkce_challenge_plain}; 103 | 104 | /* 105 | * PKCE s256 106 | */ 107 | oidc_proto_pkce_t oidc_pkce_s256 = {OIDC_PKCE_METHOD_S256, oidc_proto_pkce_state_s256, oidc_proto_pkce_verifier_s256, 108 | oidc_proto_pkce_challenge_s256}; 109 | 110 | /* 111 | * PKCE none 112 | */ 113 | oidc_proto_pkce_t oidc_pkce_none = {OIDC_PKCE_METHOD_NONE, NULL, NULL, NULL}; 114 | -------------------------------------------------------------------------------- /src/util/base64.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "util/util.h" 44 | 45 | #include 46 | /* 47 | * base64url encode a string 48 | */ 49 | int oidc_util_base64url_encode(request_rec *r, char **dst, const char *src, int src_len, int remove_padding) { 50 | if ((src == NULL) || (src_len <= 0)) { 51 | oidc_error(r, "not encoding anything; src=NULL and/or src_len<1"); 52 | return -1; 53 | } 54 | unsigned int enc_len = apr_base64_encode_len(src_len); 55 | char *enc = apr_palloc(r->pool, enc_len); 56 | apr_base64_encode(enc, src, src_len); 57 | unsigned int i = 0; 58 | while (enc[i] != '\0') { 59 | if (enc[i] == '+') 60 | enc[i] = '-'; 61 | if (enc[i] == '/') 62 | enc[i] = '_'; 63 | if (enc[i] == '=') 64 | enc[i] = ','; 65 | i++; 66 | } 67 | if (remove_padding) { 68 | /* remove /0 and padding */ 69 | if (enc_len > 0) 70 | enc_len--; 71 | if ((enc_len > 0) && (enc[enc_len - 1] == ',')) 72 | enc_len--; 73 | if ((enc_len > 0) && (enc[enc_len - 1] == ',')) 74 | enc_len--; 75 | enc[enc_len] = '\0'; 76 | } 77 | *dst = enc; 78 | return enc_len; 79 | } 80 | 81 | /* 82 | * parse a base64 encoded binary value from the provided string 83 | */ 84 | char *oidc_util_base64_decode(apr_pool_t *pool, const char *input, char **output, int *output_len) { 85 | if ((input == NULL) || (output == NULL) || (output_len == 0)) 86 | return apr_psprintf(pool, "base64-decoding of failed: invalid parameters"); 87 | 88 | *output = apr_pcalloc(pool, apr_base64_decode_len(input)); 89 | *output_len = apr_base64_decode(*output, input); 90 | 91 | if (*output_len <= 0) 92 | return apr_psprintf(pool, "base64-decoding of \"%s\" failed", input); 93 | 94 | return NULL; 95 | } 96 | 97 | /* 98 | * base64url decode a string 99 | */ 100 | int oidc_util_base64url_decode(apr_pool_t *pool, char **dst, const char *src) { 101 | if (src == NULL) { 102 | return -1; 103 | } 104 | char *dec = apr_pstrdup(pool, src); 105 | int i = 0; 106 | while (dec[i] != '\0') { 107 | if (dec[i] == '-') 108 | dec[i] = '+'; 109 | if (dec[i] == '_') 110 | dec[i] = '/'; 111 | if (dec[i] == ',') 112 | dec[i] = '='; 113 | i++; 114 | } 115 | switch (_oidc_strlen(dec) % 4) { 116 | case 0: 117 | break; 118 | case 2: 119 | dec = apr_pstrcat(pool, dec, "==", NULL); 120 | break; 121 | case 3: 122 | dec = apr_pstrcat(pool, dec, "=", NULL); 123 | break; 124 | default: 125 | return 0; 126 | } 127 | 128 | int dlen = -1; 129 | oidc_util_base64_decode(pool, dec, dst, &dlen); 130 | return dlen; 131 | } 132 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | The primary author of mod_auth_openidc is: 2 | 3 | Hans Zandbelt 4 | 5 | Thanks to the following people for contributing to mod_auth_openidc by 6 | reporting bugs, providing fixes, suggesting useful features or other: 7 | 8 | Dániel SÜTTŐ 9 | Roland Hedberg 10 | Bill Simon 11 | Jim Fox 12 | Martin Srom 13 | Dejan Latinovic 14 | Hiroyuki Wada 15 | Gunnar Scherf 16 | Terrence Fleury 17 | Jeremy Archer 18 | Forkbomber 19 | Kanthi Vaidya 20 | szakharchenko 21 | John Bradley 22 | Stefano Vercelli 23 | David Bernick 24 | Joseph Bester 25 | Daniel Pfile 26 | Rebecka Gulliksson 27 | Ryan Kelly 28 | John R. Dennis 29 | steve-dave 30 | glatzert 31 | Amit Joshi 32 | Andy Curtis 33 | solsson 34 | drdivano 35 | AliceWonderMiscreations 36 | Wouter Hund 37 | Hans Keeler 38 | Moritz Schlarb 39 | remi-cc 40 | hihellobolke 41 | Horatiu Eugen Vlad 42 | cristichiru 43 | Bono de Visser 44 | Patrick Uiterwijk 45 | Marcel Kottmann 46 | timpuri 47 | Eldar Zaitov 48 | Gergan Penkov 49 | Florian Weimer 50 | Aaron Donovan 51 | Hans Petter Bieker 52 | archzone 53 | Petteri Stenius 54 | Lance Fannin 55 | Ricardo Martin Camarero 56 | Filip Vujicic 57 | Janusz Ulanowski 58 | Aimoto Norihito 59 | Andy Lindeman 60 | Stefan Wachter 61 | Paolo Battino 62 | absynth76 63 | Aaron Jones 64 | Bryan Ingram 65 | Tim Deisser 66 | Peter Hurtenbach 67 | Paul Spangler 68 | Chris Pawling 69 | Matthias Fleschütz 70 | Harri Rautila 71 | Tatsuhiko Yasumatsu 72 | Adam Stadler 73 | Steffen Greber 74 | Iain Heggie 75 | Dirk Kok 76 | Meheni 77 | abg35 78 | Nathan Neulinger 79 | Simon Studer 80 | juur 81 | sebastian-goeldi 82 | rajeevn1 83 | Daan Bakker 84 | smanolache 85 | blackwhiser1 86 | Ruediger Pluem 87 | Nikhil Chaudhari 88 | Quentin Gillet 89 | Brent van Laere 90 | Mads Freek Petersen 91 | Stefan Richter 92 | Mattias Åsander 93 | adg-mh 94 | David P. Discher 95 | ryanwilliamnicholls 96 | Dmitrii Ermakov 97 | tarteens 98 | Atzm WATANABE 99 | Rui Ventura 100 | -------------------------------------------------------------------------------- /src/cfg/cache.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_CFG_CACHE_H_ 44 | #define _MOD_AUTH_OPENIDC_CFG_CACHE_H_ 45 | 46 | #include "cfg/cfg.h" 47 | 48 | void oidc_cfg_cache_create_server_config(oidc_cfg_t *c); 49 | void oidc_cfg_cache_merge_server_config(oidc_cfg_t *c, oidc_cfg_t *base, oidc_cfg_t *add); 50 | 51 | // NB: need the primitive strings and the custom set routines 52 | // here because the commands are included in config. 53 | 54 | #define OIDCCacheType "OIDCCacheType" 55 | #define OIDCCacheEncrypt "OIDCCacheEncrypt" 56 | 57 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_type, int) 58 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_encrypt, int) 59 | 60 | /* 61 | * shm 62 | */ 63 | #define OIDCCacheShmMax "OIDCCacheShmMax" 64 | #define OIDCCacheShmEntrySizeMax "OIDCCacheShmEntrySizeMax" 65 | 66 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_shm_size_max, int) 67 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_shm_entry_size_max, int) 68 | 69 | /* 70 | * file 71 | */ 72 | 73 | #define OIDCCacheDir "OIDCCacheDir" 74 | #define OIDCCacheFileCleanInterval "OIDCCacheFileCleanInterval" 75 | 76 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_file_clean_interval, int) 77 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_file_dir, const char *) 78 | 79 | /* 80 | * memcache 81 | */ 82 | 83 | #ifdef USE_MEMCACHE 84 | 85 | #define OIDCMemCacheServers "OIDCMemCacheServers" 86 | #define OIDCMemCacheConnectionsMin "OIDCMemCacheConnectionsMin" 87 | #define OIDCMemCacheConnectionsSMax "OIDCMemCacheConnectionsSMax" 88 | #define OIDCMemCacheConnectionsHMax "OIDCMemCacheConnectionsHMax" 89 | #define OIDCMemCacheConnectionsTTL "OIDCMemCacheConnectionsTTL" 90 | 91 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_memcache_servers, const char *) 92 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_memcache_min, int) 93 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_memcache_smax, int) 94 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_memcache_hmax, int) 95 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_memcache_ttl, apr_interval_time_t) 96 | 97 | #endif // USE_MEMCACHE 98 | 99 | /* 100 | * redis 101 | */ 102 | 103 | #ifdef USE_LIBHIREDIS 104 | 105 | #define OIDCRedisCacheServer "OIDCRedisCacheServer" 106 | #define OIDCRedisCacheUsername "OIDCRedisCacheUsername" 107 | #define OIDCRedisCachePassword "OIDCRedisCachePassword" 108 | #define OIDCRedisCacheDatabase "OIDCRedisCacheDatabase" 109 | #define OIDCRedisCacheConnectTimeout "OIDCRedisCacheConnectTimeout" 110 | #define OIDCRedisCacheTimeout "OIDCRedisCacheTimeout" 111 | 112 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_redis_server, const char *) 113 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_redis_username, const char *) 114 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_redis_password, const char *) 115 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_redis_database, int) 116 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_redis_timeout, int) 117 | OIDC_CFG_MEMBER_FUNCS_DECL(cache_redis_connect_timeout, int, const char *) 118 | OIDC_CFG_MEMBER_FUNC_GET_DECL(cache_redis_keepalive, int) 119 | 120 | #endif // USE_LIBHIREDIS 121 | 122 | #endif // _MOD_AUTH_OPENIDC_CFG_CACHE_H_ 123 | -------------------------------------------------------------------------------- /src/util/random.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "util/util.h" 44 | 45 | #ifdef USE_URANDOM 46 | 47 | #include 48 | #include 49 | #include 50 | 51 | #define DEV_RANDOM "/dev/urandom" 52 | 53 | #endif 54 | 55 | /* 56 | * generate a number of random bytes, either using libapr or urandom (no per-request logging) 57 | */ 58 | static apr_byte_t _oidc_util_rand(unsigned char *buf, apr_size_t length) { 59 | apr_byte_t rv = FALSE; 60 | 61 | #ifndef USE_URANDOM 62 | 63 | rv = (apr_generate_random_bytes(buf, length) == APR_SUCCESS); 64 | 65 | #else 66 | 67 | int fd = -1; 68 | 69 | do { 70 | apr_ssize_t rc; 71 | 72 | if (fd == -1) { 73 | fd = open(DEV_RANDOM, O_RDONLY); 74 | if (fd == -1) 75 | return FALSE; 76 | } 77 | 78 | do { 79 | rc = read(fd, buf, length); 80 | } while (rc == -1 && errno == EINTR); 81 | 82 | if (rc < 0) { 83 | int errnum = errno; 84 | close(fd); 85 | return FALSE; 86 | } else if (rc == 0) { 87 | close(fd); 88 | fd = -1; /* force open() again */ 89 | } else { 90 | buf += rc; 91 | length -= rc; 92 | } 93 | } while (length > 0); 94 | 95 | close(fd); 96 | 97 | rv = TRUE; 98 | 99 | #endif 100 | 101 | return rv; 102 | } 103 | 104 | /* 105 | * generate a number of random bytes, either using libapr or urandom 106 | */ 107 | static apr_byte_t _oidc_util_rand_bytes(request_rec *r, unsigned char *buf, apr_size_t len) { 108 | apr_byte_t rv = TRUE; 109 | #ifndef USE_URANDOM 110 | const char *gen = "apr"; 111 | #else 112 | const char *gen = DEV_RANDOM; 113 | #endif 114 | if (r) 115 | oidc_debug(r, "use [%s] for generating %" APR_SIZE_T_FMT " random bytes", gen, len); 116 | rv = _oidc_util_rand(buf, len); 117 | if (r) 118 | oidc_debug(r, "return: %d", rv); 119 | return rv; 120 | } 121 | 122 | /* 123 | * generate a random integer value in the specified modulo range 124 | */ 125 | unsigned int oidc_util_rand_int(unsigned int mod) { 126 | unsigned int v; 127 | _oidc_util_rand((unsigned char *)&v, sizeof(v)); 128 | return v % mod; 129 | } 130 | 131 | /* 132 | * generate a random string of base64url encoded characters, representing len bytes 133 | */ 134 | apr_byte_t oidc_util_rand_str(request_rec *r, char **str, int len) { 135 | unsigned char *bytes = apr_pcalloc(r->pool, len); 136 | if (_oidc_util_rand_bytes(r, bytes, len) != TRUE) { 137 | oidc_error(r, "_oidc_util_rand_bytes returned an error"); 138 | return FALSE; 139 | } 140 | if (oidc_util_base64url_encode(r, str, (const char *)bytes, len, TRUE) <= 0) { 141 | oidc_error(r, "oidc_base64url_encode returned an error"); 142 | return FALSE; 143 | } 144 | return TRUE; 145 | } 146 | 147 | /* 148 | * generate a random string of (lowercase) hexadecimal characters, representing len bytes 149 | */ 150 | char *oidc_util_rand_hex_str(request_rec *r, apr_pool_t *pool, int len) { 151 | unsigned char *bytes = apr_pcalloc(pool, len); 152 | if (_oidc_util_rand_bytes(r, bytes, len) != TRUE) { 153 | if (r) 154 | oidc_error(r, "_oidc_util_rand_bytes returned an error"); 155 | return NULL; 156 | } 157 | return oidc_util_hex_encode(pool, bytes, len); 158 | } 159 | -------------------------------------------------------------------------------- /src/proto/proto.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "proto/proto.h" 44 | #include "cfg/dir.h" 45 | #include "cfg/parse.h" 46 | #include "handle/handle.h" 47 | #include "metadata.h" 48 | #include "metrics.h" 49 | #include "mod_auth_openidc.h" 50 | #include "util/util.h" 51 | 52 | #include 53 | #include 54 | 55 | /* nonce bytes length */ 56 | #define OIDC_PROTO_NONCE_LENGTH 32 57 | 58 | /* 59 | * generate a random value (nonce) to correlate request/response through browser state 60 | */ 61 | apr_byte_t oidc_proto_nonce_gen(request_rec *r, char **nonce) { 62 | return oidc_util_rand_str(r, nonce, OIDC_PROTO_NONCE_LENGTH); 63 | } 64 | 65 | /* jti bytes length */ 66 | #define OIDC_PROTO_JWT_JTI_LEN 16 67 | 68 | /* 69 | * generate a random unique "jti" JWT identifier 70 | */ 71 | char *oidc_proto_jti_gen(request_rec *r) { 72 | char *jti = NULL; 73 | if (oidc_util_rand_str(r, &jti, OIDC_PROTO_JWT_JTI_LEN) == FALSE) { 74 | oidc_error(r, "oidc_util_rand_str returned FALSE"); 75 | } 76 | return jti; 77 | } 78 | 79 | /* 80 | * return the supported flows 81 | */ 82 | apr_array_header_t *oidc_proto_supported_flows(apr_pool_t *pool) { 83 | apr_array_header_t *result = apr_array_make(pool, 6, sizeof(const char *)); 84 | APR_ARRAY_PUSH(result, const char *) = OIDC_PROTO_RESPONSE_TYPE_CODE; 85 | APR_ARRAY_PUSH(result, const char *) = OIDC_PROTO_RESPONSE_TYPE_IDTOKEN; 86 | APR_ARRAY_PUSH(result, const char *) = OIDC_PROTO_RESPONSE_TYPE_IDTOKEN_TOKEN; 87 | APR_ARRAY_PUSH(result, const char *) = OIDC_PROTO_RESPONSE_TYPE_CODE_IDTOKEN; 88 | APR_ARRAY_PUSH(result, const char *) = OIDC_PROTO_RESPONSE_TYPE_CODE_TOKEN; 89 | APR_ARRAY_PUSH(result, const char *) = OIDC_PROTO_RESPONSE_TYPE_CODE_IDTOKEN_TOKEN; 90 | return result; 91 | } 92 | 93 | /* 94 | * check if a particular OpenID Connect flow is supported 95 | */ 96 | apr_byte_t oidc_proto_flow_is_supported(apr_pool_t *pool, const char *flow) { 97 | apr_array_header_t *flows = oidc_proto_supported_flows(pool); 98 | int i; 99 | for (i = 0; i < flows->nelts; i++) { 100 | if (oidc_util_spaced_string_equals(pool, flow, APR_ARRAY_IDX(flows, i, const char *))) 101 | return TRUE; 102 | } 103 | return FALSE; 104 | } 105 | 106 | /* 107 | * set the WWW-Authenticate response header according to https://tools.ietf.org/html/rfc6750#section-3 108 | */ 109 | int oidc_proto_return_www_authenticate(request_rec *r, const char *error, const char *error_description) { 110 | apr_byte_t accept_token_in = oidc_cfg_dir_oauth_accept_token_in_get(r); 111 | char *hdr; 112 | if (accept_token_in == OIDC_OAUTH_ACCEPT_TOKEN_IN_BASIC) { 113 | hdr = apr_psprintf(r->pool, "%s", OIDC_PROTO_BASIC); 114 | } else { 115 | hdr = apr_psprintf(r->pool, "%s", OIDC_PROTO_BEARER); 116 | } 117 | 118 | if (ap_auth_name(r) != NULL) 119 | hdr = apr_psprintf(r->pool, "%s %s=\"%s\"", hdr, OIDC_PROTO_REALM, ap_auth_name(r)); 120 | if (error != NULL) 121 | hdr = 122 | apr_psprintf(r->pool, "%s%s %s=\"%s\"", hdr, (ap_auth_name(r) ? "," : ""), OIDC_PROTO_ERROR, error); 123 | if (error_description != NULL) 124 | hdr = apr_psprintf(r->pool, "%s, %s=\"%s\"", hdr, OIDC_PROTO_ERROR_DESCRIPTION, error_description); 125 | oidc_http_hdr_err_out_add(r, OIDC_HTTP_HDR_WWW_AUTHENTICATE, hdr); 126 | return HTTP_UNAUTHORIZED; 127 | } 128 | -------------------------------------------------------------------------------- /src/cfg/parse.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_CFG_PARSE_H_ 44 | #define _MOD_AUTH_OPENIDC_CFG_PARSE_H_ 45 | 46 | #include "cfg/cfg.h" 47 | 48 | typedef struct oidc_cfg_option_t { 49 | int val; 50 | char *str; 51 | } oidc_cfg_option_t; 52 | 53 | char *oidc_cfg_parse_option(apr_pool_t *pool, const oidc_cfg_option_t options[], int n, const char *arg, int *v); 54 | char *oidc_cfg_parse_option_ignore_case(apr_pool_t *pool, const oidc_cfg_option_t options[], int n, const char *arg, 55 | int *v); 56 | char *oidc_cfg_parse_options_flatten(apr_pool_t *pool, const oidc_cfg_option_t options[], int n); 57 | 58 | char *oidc_cfg_parse_flatten_options(apr_pool_t *pool, const char *options[]); 59 | const char *oidc_cfg_parse_is_valid_option(apr_pool_t *pool, const char *arg, const char *options[]); 60 | const char *oidc_cfg_parse_is_valid_int(apr_pool_t *pool, int value, int min_value, int max_value); 61 | const char *oidc_cfg_parse_is_valid_url(apr_pool_t *pool, const char *arg, const char *scheme); 62 | const char *oidc_cfg_parse_is_valid_http_url(apr_pool_t *pool, const char *arg); 63 | const char *oidc_cfg_parse_is_valid_response_type(apr_pool_t *pool, const char *arg); 64 | const char *oidc_cfg_parse_is_valid_response_mode(apr_pool_t *pool, const char *arg); 65 | const char *oidc_cfg_parse_is_valid_signed_response_alg(apr_pool_t *pool, const char *arg); 66 | const char *oidc_cfg_parse_is_valid_encrypted_response_alg(apr_pool_t *pool, const char *arg); 67 | const char *oidc_cfg_parse_is_valid_encrypted_response_enc(apr_pool_t *pool, const char *arg); 68 | 69 | const char *oidc_cfg_parse_boolean(apr_pool_t *pool, const char *arg, int *bool_value); 70 | const char *oidc_cfg_parse_int(apr_pool_t *pool, const char *arg, int *int_value); 71 | const char *oidc_cfg_parse_int_min_max(apr_pool_t *pool, const char *arg, int *int_value, int min_value, int max_value); 72 | const char *oidc_cfg_parse_timeout_min_max(apr_pool_t *pool, const char *arg, apr_interval_time_t *timeout_value, 73 | apr_interval_time_t min_value, apr_interval_time_t max_value); 74 | const char *oidc_cfg_parse_dirname(apr_pool_t *pool, const char *arg, char **value); 75 | const char *oidc_cfg_parse_filename(apr_pool_t *pool, const char *arg, char **value); 76 | const char *oidc_cfg_parse_relative_or_absolute_url(apr_pool_t *pool, const char *arg, char **value); 77 | const char *oidc_cfg_parse_key_record(apr_pool_t *pool, const char *tuple, char **kid, char **key, int *key_len, 78 | char **use, apr_byte_t triplet); 79 | const char *oidc_cfg_parse_action_on_error_refresh_as(apr_pool_t *pool, const char *arg, 80 | oidc_on_error_action_t *action); 81 | const char *oidc_cfg_parse_passphrase(apr_pool_t *pool, const char *arg, char **passphrase); 82 | const char *oidc_cfg_parse_public_key_files(apr_pool_t *pool, const char *arg, apr_array_header_t **keys); 83 | 84 | typedef const char *(*oidc_valid_function_t)(apr_pool_t *, const char *); 85 | 86 | oidc_valid_function_t oidc_cfg_get_valid_endpoint_auth_function(oidc_cfg_t *cfg); 87 | const char *oidc_parse_remote_user_claim(apr_pool_t *pool, const char *v1, const char *v2, const char *v3, 88 | oidc_remote_user_claim_t *remote_user_claim); 89 | const char *oidc_cfg_parse_http_timeout(apr_pool_t *pool, const char *arg1, const char *arg2, const char *arg3, 90 | oidc_http_timeout_t *http_timeout); 91 | 92 | #endif // _MOD_AUTH_OPENIDC_CFG_PARSE_H_ 93 | -------------------------------------------------------------------------------- /src/proto/dpop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "mod_auth_openidc.h" 44 | #include "proto/proto.h" 45 | #include "util/util.h" 46 | 47 | #define OIDC_PROTO_DPOP_JWT_TYP "dpop+jwt" 48 | 49 | apr_byte_t oidc_proto_dpop_use_nonce(request_rec *r, oidc_cfg_t *cfg, json_t *j_result, apr_hash_t *response_hdrs, 50 | const char *url, const char *method, const char *access_token, char **dpop) { 51 | apr_byte_t rv = FALSE; 52 | char *dpop_nonce = NULL; 53 | 54 | json_t *j_error = json_object_get(j_result, OIDC_PROTO_ERROR); 55 | if ((j_error == NULL) || (!json_is_string(j_error)) || 56 | (_oidc_strcmp(json_string_value(j_error), OIDC_PROTO_DPOP_USE_NONCE) != 0)) 57 | goto end; 58 | 59 | /* try again with a DPoP nonce provided by the server */ 60 | dpop_nonce = (char *)apr_hash_get(response_hdrs, OIDC_HTTP_HDR_DPOP_NONCE, APR_HASH_KEY_STRING); 61 | if (dpop_nonce == NULL) { 62 | oidc_error(r, "error is \"%s\" but no \"%s\" header found", OIDC_PROTO_DPOP_USE_NONCE, 63 | OIDC_HTTP_HDR_DPOP_NONCE); 64 | goto end; 65 | } 66 | 67 | rv = oidc_proto_dpop_create(r, cfg, url, method, access_token, dpop_nonce, dpop); 68 | 69 | end: 70 | 71 | oidc_debug(r, "leave: %d, dpop=%s", rv, *dpop ? "true" : "false"); 72 | 73 | return rv; 74 | } 75 | 76 | /* 77 | * generate a DPoP proof for the specified URL/method/access_token 78 | */ 79 | apr_byte_t oidc_proto_dpop_create(request_rec *r, oidc_cfg_t *cfg, const char *url, const char *method, 80 | const char *access_token, const char *nonce, char **dpop) { 81 | apr_byte_t rv = FALSE; 82 | oidc_jwt_t *jwt = NULL; 83 | oidc_jwk_t *jwk = NULL; 84 | oidc_jose_error_t err; 85 | cjose_err cjose_err; 86 | char *s_jwk = NULL; 87 | char *ath = NULL; 88 | 89 | oidc_debug(r, "enter"); 90 | 91 | if (oidc_proto_jwt_create_from_first_pkey(r, cfg, &jwk, &jwt, TRUE) == FALSE) 92 | goto end; 93 | 94 | json_object_set_new(jwt->header.value.json, OIDC_CLAIM_TYP, json_string(OIDC_PROTO_DPOP_JWT_TYP)); 95 | s_jwk = cjose_jwk_to_json(jwk->cjose_jwk, 0, &cjose_err); 96 | cjose_header_set_raw(jwt->header.value.json, OIDC_CLAIM_JWK, s_jwk, &cjose_err); 97 | 98 | json_object_set_new(jwt->payload.value.json, OIDC_CLAIM_JTI, json_string(oidc_proto_jti_gen(r))); 99 | json_object_set_new(jwt->payload.value.json, OIDC_CLAIM_HTM, json_string(method)); 100 | json_object_set_new(jwt->payload.value.json, OIDC_CLAIM_HTU, json_string(url)); 101 | json_object_set_new(jwt->payload.value.json, OIDC_CLAIM_IAT, json_integer(apr_time_sec(apr_time_now()))); 102 | 103 | if (access_token != NULL) { 104 | if (oidc_jose_hash_and_base64url_encode(r->pool, OIDC_JOSE_ALG_SHA256, access_token, 105 | _oidc_strlen(access_token), &ath, &err) == FALSE) { 106 | oidc_error(r, "oidc_jose_hash_and_base64url_encode failed: %s", oidc_jose_e2s(r->pool, err)); 107 | goto end; 108 | } 109 | json_object_set_new(jwt->payload.value.json, OIDC_CLAIM_ATH, json_string(ath)); 110 | } 111 | 112 | if (nonce != NULL) 113 | json_object_set_new(jwt->payload.value.json, OIDC_CLAIM_NONCE, json_string(nonce)); 114 | 115 | if (oidc_proto_jwt_sign_and_serialize(r, jwk, jwt, dpop) == FALSE) 116 | goto end; 117 | 118 | rv = TRUE; 119 | 120 | end: 121 | 122 | if (s_jwk) 123 | cjose_get_dealloc()(s_jwk); 124 | 125 | if (jwt) 126 | oidc_jwt_destroy(jwt); 127 | 128 | return rv; 129 | } 130 | -------------------------------------------------------------------------------- /src/handle/dpop.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "handle/handle.h" 44 | #include "mod_auth_openidc.h" 45 | #include "proto/proto.h" 46 | #include "util/util.h" 47 | 48 | #include 49 | 50 | #define OIDC_DPOP_PARAM_URL "url" 51 | #define OIDC_DPOP_PARAM_NONCE "nonce" 52 | #define OIDC_DPOP_PARAM_METHOD "method" 53 | 54 | int oidc_dpop_request(request_rec *r, oidc_cfg_t *c) { 55 | int rc = HTTP_BAD_REQUEST; 56 | char *s_url = NULL; 57 | char *s_access_token = NULL; 58 | char *s_nonce = NULL; 59 | char *s_method = NULL; 60 | char *s_dpop = NULL; 61 | char *s_response = NULL; 62 | json_t *json = NULL; 63 | char *remote_ip = NULL; 64 | 65 | #if AP_MODULE_MAGIC_AT_LEAST(20111130, 0) 66 | remote_ip = r->useragent_ip; 67 | #else 68 | remote_ip = r->connection->remote_ip; 69 | #endif 70 | 71 | if (!oidc_cfg_dpop_api_enabled_get(c)) { 72 | oidc_error(r, "DPoP hook called but the DPoP API is not enabled in %s", OIDCDPoPMode); 73 | goto end; 74 | } 75 | 76 | /* try to make sure that the proof-of-possession semantics are preserved */ 77 | if ((_oidc_strnatcasecmp(remote_ip, r->connection->local_ip) != 0) && 78 | (apr_table_get(r->subprocess_env, "OIDC_DPOP_API_INSECURE") == 0)) { 79 | oidc_warn( 80 | r, 81 | "reject DPoP creation request from remote host: you should create a separate virtual (sub)host " 82 | "that requires client certificate authentication to allow and proxy this request (remote_ip=%s, " 83 | "r->connection->local_ip=%s)", 84 | remote_ip, r->connection->local_ip); 85 | rc = HTTP_UNAUTHORIZED; 86 | goto end; 87 | } 88 | 89 | /* retrieve the access token parameter */ 90 | oidc_util_url_parameter_get(r, OIDC_REDIRECT_URI_REQUEST_DPOP, &s_access_token); 91 | if (s_access_token == NULL) { 92 | oidc_error(r, "\"access_token\" value to the \"%s\" parameter is missing", 93 | OIDC_REDIRECT_URI_REQUEST_DPOP); 94 | goto end; 95 | } 96 | 97 | /* retrieve the URL parameter */ 98 | oidc_util_url_parameter_get(r, OIDC_DPOP_PARAM_URL, &s_url); 99 | if (s_url == NULL) { 100 | oidc_error(r, "\"url\" parameter is missing"); 101 | goto end; 102 | } 103 | 104 | /* retrieve the optional nonce parameter */ 105 | oidc_util_url_parameter_get(r, OIDC_DPOP_PARAM_NONCE, &s_nonce); 106 | 107 | /* parse the optional HTTP method parameter */ 108 | oidc_util_url_parameter_get(r, OIDC_DPOP_PARAM_METHOD, &s_method); 109 | if (_oidc_strnatcasecmp(s_method, "post") == 0) 110 | s_method = "POST"; 111 | else if ((_oidc_strnatcasecmp(s_method, "get") == 0) || (s_method == NULL)) 112 | s_method = "GET"; 113 | 114 | /* create the DPoP header value */ 115 | if ((oidc_proto_dpop_create(r, c, s_url, s_method, s_access_token, s_nonce, &s_dpop) == FALSE) || 116 | (s_dpop == NULL)) { 117 | oidc_error(r, "creating the DPoP proof value failed"); 118 | rc = HTTP_INTERNAL_SERVER_ERROR; 119 | goto end; 120 | } 121 | 122 | /* assemble and serialize the JSON response object */ 123 | json = json_object(); 124 | json_object_set_new(json, OIDC_HTTP_HDR_DPOP, json_string(s_dpop)); 125 | s_response = oidc_util_json_encode(r->pool, json, JSON_COMPACT | JSON_PRESERVE_ORDER); 126 | 127 | /* return the serialized JSON response */ 128 | rc = oidc_util_http_send(r, s_response, _oidc_strlen(s_response), OIDC_HTTP_CONTENT_TYPE_JSON, OK); 129 | 130 | end: 131 | 132 | if (json) 133 | json_decref(json); 134 | 135 | return rc; 136 | } 137 | -------------------------------------------------------------------------------- /src/proto/profile.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "proto/proto.h" 44 | 45 | /* 46 | * returns the "aud" claim to insert into the JWT used for client 47 | * authentication towards the token endpoint using private_key_jwt/client_secret_jwt 48 | */ 49 | const char *oidc_proto_profile_token_endpoint_auth_aud(oidc_provider_t *provider) { 50 | if (oidc_cfg_provider_profile_get(provider) == OIDC_PROFILE_FAPI20) { 51 | return oidc_cfg_provider_issuer_get(provider); 52 | } 53 | return oidc_cfg_provider_token_endpoint_url_get(provider); 54 | } 55 | 56 | /* 57 | * returns the "aud" claim to insert into the JWT used for client 58 | * authentication towards the revocation endpoint using private_key_jwt/client_secret_jwt 59 | */ 60 | const char *oidc_proto_profile_revocation_endpoint_auth_aud(oidc_provider_t *provider, const char *val) { 61 | if (oidc_cfg_provider_profile_get(provider) == OIDC_PROFILE_FAPI20) { 62 | return oidc_cfg_provider_issuer_get(provider); 63 | } 64 | const char *aud = oidc_cfg_provider_revocation_endpoint_url_get(provider); 65 | if (val != NULL) { 66 | if (_oidc_strcmp(val, "token") == 0) { 67 | aud = oidc_cfg_provider_token_endpoint_url_get(provider); 68 | } else { 69 | aud = val; 70 | } 71 | } 72 | return aud; 73 | } 74 | 75 | /* 76 | * returns the method to be used when sending the authorization request to the Provider 77 | */ 78 | oidc_auth_request_method_t oidc_proto_profile_auth_request_method_get(oidc_provider_t *provider) { 79 | if (oidc_cfg_provider_profile_get(provider) == OIDC_PROFILE_FAPI20) 80 | return OIDC_AUTH_REQUEST_METHOD_PAR; 81 | return oidc_cfg_provider_auth_request_method_get(provider); 82 | } 83 | 84 | /* 85 | * returns the acceptable "aud" values in the ID token 86 | */ 87 | const apr_array_header_t *oidc_proto_profile_id_token_aud_values_get(apr_pool_t *pool, oidc_provider_t *provider) { 88 | const apr_array_header_t *values = oidc_cfg_provider_id_token_aud_values_get(provider); 89 | // TODO: so we actually do allow overriding the acceptable "aud" values but we sort of assume the client_id 90 | // is in there in that case; perhaps check that - in the config check? - for FAPI20 91 | if (values == NULL) { 92 | if (oidc_cfg_provider_profile_get(provider) == OIDC_PROFILE_FAPI20) { 93 | apr_array_header_t *list = NULL; 94 | oidc_cfg_string_list_add(pool, &list, oidc_cfg_provider_client_id_get(provider)); 95 | return list; 96 | } 97 | } 98 | return values; 99 | } 100 | 101 | /* 102 | * returns the PKCE mode 103 | */ 104 | const oidc_proto_pkce_t *oidc_proto_profile_pkce_get(oidc_provider_t *provider) { 105 | if (oidc_cfg_provider_profile_get(provider) == OIDC_PROFILE_FAPI20) 106 | return &oidc_pkce_s256; 107 | return oidc_cfg_provider_pkce_get(provider); 108 | } 109 | 110 | /* 111 | * returns the DPoP mode 112 | */ 113 | oidc_dpop_mode_t oidc_proto_profile_dpop_mode_get(oidc_provider_t *provider) { 114 | if (oidc_cfg_provider_profile_get(provider) == OIDC_PROFILE_FAPI20) 115 | return OIDC_DPOP_MODE_REQUIRED; 116 | return oidc_cfg_provider_dpop_mode_get(provider); 117 | } 118 | 119 | /* 120 | * returns whether the Provider is required to pass back an "iss" parameter 121 | * together with the authorization response sent to the Redirect URI 122 | */ 123 | int oidc_proto_profile_response_require_iss_get(oidc_provider_t *provider) { 124 | if (oidc_cfg_provider_profile_get(provider) == OIDC_PROFILE_FAPI20) 125 | return 1; 126 | return oidc_cfg_provider_response_require_iss_get(provider); 127 | } 128 | -------------------------------------------------------------------------------- /src/util/key.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "util/util.h" 44 | 45 | /* 46 | * create a symmetric key from a client_secret 47 | */ 48 | apr_byte_t oidc_util_key_symmetric_create(request_rec *r, const char *client_secret, unsigned int r_key_len, 49 | const char *hash_algo, apr_byte_t set_kid, oidc_jwk_t **jwk) { 50 | oidc_jose_error_t err = {{'\0'}, 0, {'\0'}, {'\0'}}; 51 | unsigned char *key = NULL; 52 | unsigned int key_len; 53 | 54 | if ((client_secret != NULL) && (_oidc_strlen(client_secret) > 0)) { 55 | 56 | if (hash_algo == NULL) { 57 | key = (unsigned char *)client_secret; 58 | key_len = _oidc_strlen(client_secret); 59 | } else { 60 | /* hash the client_secret first, this is OpenID Connect specific */ 61 | if (oidc_jose_hash_bytes(r->pool, hash_algo, (const unsigned char *)client_secret, 62 | _oidc_strlen(client_secret), &key, &key_len, &err) == FALSE) 63 | return FALSE; 64 | } 65 | 66 | if ((key != NULL) && (key_len > 0)) { 67 | if ((r_key_len != 0) && (key_len >= r_key_len)) 68 | key_len = r_key_len; 69 | oidc_debug(r, "key_len=%d", key_len); 70 | *jwk = oidc_jwk_create_symmetric_key(r->pool, NULL, key, key_len, set_kid, &err); 71 | } 72 | 73 | if (*jwk == NULL) { 74 | oidc_error(r, "could not create JWK from the provided secret: %s", oidc_jose_e2s(r->pool, err)); 75 | return FALSE; 76 | } 77 | } 78 | 79 | return TRUE; 80 | } 81 | 82 | /* 83 | * merge an array of JWKs and a JWK into a single hashtable 84 | */ 85 | apr_hash_t *oidc_util_key_symmetric_merge(apr_pool_t *pool, const apr_array_header_t *keys, oidc_jwk_t *jwk) { 86 | apr_hash_t *result = apr_hash_make(pool); 87 | const oidc_jwk_t *elem = NULL; 88 | int i = 0; 89 | if (keys != NULL) { 90 | for (i = 0; i < keys->nelts; i++) { 91 | elem = APR_ARRAY_IDX(keys, i, const oidc_jwk_t *); 92 | if (elem->kid != NULL) 93 | apr_hash_set(result, elem->kid, APR_HASH_KEY_STRING, elem); 94 | } 95 | } 96 | if (jwk != NULL) { 97 | apr_hash_set(result, jwk->kid, APR_HASH_KEY_STRING, jwk); 98 | } 99 | return result; 100 | } 101 | 102 | /* 103 | * merge the provided array of keys (k2) into a hash table of keys (k1) 104 | */ 105 | apr_hash_t *oidc_util_key_sets_merge(apr_pool_t *pool, apr_hash_t *k1, const apr_array_header_t *k2) { 106 | apr_hash_t *rv = k1 ? apr_hash_copy(pool, k1) : apr_hash_make(pool); 107 | const oidc_jwk_t *jwk = NULL; 108 | int i = 0; 109 | if (k2 != NULL) { 110 | for (i = 0; i < k2->nelts; i++) { 111 | jwk = APR_ARRAY_IDX(k2, i, const oidc_jwk_t *); 112 | if (jwk->kid != NULL) 113 | apr_hash_set(rv, jwk->kid, APR_HASH_KEY_STRING, jwk); 114 | } 115 | } 116 | return rv; 117 | } 118 | 119 | /* 120 | * merge two hash tables with key sets 121 | */ 122 | apr_hash_t *oidc_util_key_sets_hash_merge(apr_pool_t *pool, apr_hash_t *k1, apr_hash_t *k2) { 123 | if (k1 == NULL) { 124 | if (k2 == NULL) 125 | return apr_hash_make(pool); 126 | return k2; 127 | } 128 | if (k2 == NULL) 129 | return k1; 130 | return apr_hash_overlay(pool, k1, k2); 131 | } 132 | 133 | /* 134 | * return the first JWK that matches a provided key type and use from an array of JWKs 135 | */ 136 | oidc_jwk_t *oidc_util_key_list_first(const apr_array_header_t *key_list, int kty, const char *use) { 137 | oidc_jwk_t *rv = NULL; 138 | int i = 0; 139 | oidc_jwk_t *jwk = NULL; 140 | for (i = 0; (key_list) && (i < key_list->nelts); i++) { 141 | jwk = APR_ARRAY_IDX(key_list, i, oidc_jwk_t *); 142 | if ((kty != -1) && (jwk->kty != kty)) 143 | continue; 144 | if (((use == NULL) || (jwk->use == NULL) || (_oidc_strncmp(jwk->use, use, _oidc_strlen(use)) == 0))) { 145 | rv = jwk; 146 | break; 147 | } 148 | } 149 | return rv; 150 | } 151 | -------------------------------------------------------------------------------- /src/util/jq.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "util/util.h" 44 | 45 | #ifdef USE_LIBJQ 46 | 47 | #include 48 | /* 49 | * execute a JQ expression 50 | */ 51 | static const char *oidc_util_jq_exec(request_rec *r, jq_state *jq, struct jv_parser *parser) { 52 | const char *rv = NULL; 53 | jv value, elem, str, msg; 54 | 55 | while (jv_is_valid((value = jv_parser_next(parser)))) { 56 | jq_start(jq, value, 0); 57 | while (jv_is_valid(elem = jq_next(jq))) { 58 | str = jv_dump_string(elem, 0); 59 | rv = apr_pstrdup(r->pool, jv_string_value(str)); 60 | oidc_debug(r, "jv_dump_string: %s", rv); 61 | jv_free(str); 62 | } 63 | jv_free(elem); 64 | } 65 | 66 | if (jv_invalid_has_msg(jv_copy(value))) { 67 | msg = jv_invalid_get_msg(value); 68 | oidc_error(r, "invalid: %s", jv_string_value(msg)); 69 | jv_free(msg); 70 | } else { 71 | jv_free(value); 72 | } 73 | 74 | return rv; 75 | } 76 | 77 | #define OIDC_JQ_FILTER_EXPIRE_DEFAULT 600 78 | #define OIDC_JQ_FILTER_CACHE_TTL_ENVVAR "OIDC_JQ_FILTER_CACHE_TTL" 79 | 80 | /* 81 | * return the JQ expression result cache expiry 82 | */ 83 | static int oidc_jq_filter_cache_ttl(request_rec *r) { 84 | const char *s_ttl = apr_table_get(r->subprocess_env, OIDC_JQ_FILTER_CACHE_TTL_ENVVAR); 85 | return _oidc_str_to_int(s_ttl, OIDC_JQ_FILTER_EXPIRE_DEFAULT); 86 | } 87 | 88 | #endif 89 | 90 | /* 91 | * apply a JQ expression/filter to the provided JSON input 92 | */ 93 | const char *oidc_util_jq_filter(request_rec *r, json_t *json, const char *filter) { 94 | const char *result = NULL; 95 | #ifdef USE_LIBJQ 96 | const char *input = oidc_util_json_encode(r->pool, json, JSON_PRESERVE_ORDER | JSON_COMPACT); 97 | jq_state *jq = NULL; 98 | struct jv_parser *parser = NULL; 99 | int ttl = 0; 100 | char *key = NULL; 101 | char *value = NULL; 102 | 103 | if (filter == NULL) { 104 | oidc_debug(r, "filter is NULL, abort"); 105 | result = input; 106 | goto end; 107 | } 108 | 109 | if (input == NULL) { 110 | oidc_debug(r, "input is NULL, set to empty object"); 111 | input = "{}"; 112 | } 113 | 114 | oidc_debug(r, "processing input: %s", input); 115 | oidc_debug(r, "processing filter: %s", filter); 116 | 117 | ttl = oidc_jq_filter_cache_ttl(r); 118 | if (ttl > 0) { 119 | if (oidc_util_hash_string_and_base64url_encode( 120 | r, OIDC_JOSE_ALG_SHA256, apr_pstrcat(r->pool, input, filter, NULL), &key) == FALSE) { 121 | oidc_error(r, "oidc_util_hash_string_and_base64url_encode returned an error"); 122 | goto end; 123 | } 124 | oidc_cache_get_jq_filter(r, key, &value); 125 | if (value != NULL) { 126 | oidc_debug(r, "return cached result: %s", value); 127 | result = value; 128 | goto end; 129 | } 130 | } 131 | 132 | jq = jq_init(); 133 | if (jq == NULL) { 134 | oidc_error(r, "jq_init returned NULL"); 135 | result = input; 136 | goto end; 137 | } 138 | 139 | if (jq_compile(jq, filter) == 0) { 140 | oidc_error(r, "jq_compile returned an error"); 141 | result = input; 142 | goto end; 143 | } 144 | 145 | parser = jv_parser_new(0); 146 | if (parser == NULL) { 147 | oidc_error(r, "jv_parser_new returned NULL"); 148 | result = input; 149 | goto end; 150 | } 151 | 152 | jv_parser_set_buf(parser, input, _oidc_strlen(input), 0); 153 | 154 | result = oidc_util_jq_exec(r, jq, parser); 155 | 156 | if ((result != NULL) && (ttl != 0)) { 157 | oidc_debug(r, "caching result: %s", result); 158 | oidc_cache_set_jq_filter(r, key, result, apr_time_now() + apr_time_from_sec(ttl)); 159 | } 160 | 161 | end: 162 | 163 | if (parser) 164 | jv_parser_free(parser); 165 | if (jq) 166 | jq_teardown(&jq); 167 | #else 168 | result = oidc_util_json_encode(r->pool, json, JSON_PRESERVE_ORDER | JSON_COMPACT); 169 | #endif 170 | 171 | return result; 172 | } 173 | -------------------------------------------------------------------------------- /src/util/expr.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "util/pcre_subst.h" 44 | #include "util/util.h" 45 | 46 | /* 47 | * regexp substitute 48 | * Example: 49 | * regex: "^.*([0-9]+).*$" 50 | * replace: "$1" 51 | * text_original: "match 292 numbers" 52 | * text_replaced: "292" 53 | */ 54 | apr_byte_t oidc_util_regexp_substitute(apr_pool_t *pool, const char *input, const char *regexp, const char *replace, 55 | char **output, char **error_str) { 56 | 57 | char *substituted = NULL; 58 | apr_byte_t rc = FALSE; 59 | 60 | struct oidc_pcre *preg = oidc_pcre_compile(pool, regexp, error_str); 61 | if (preg == NULL) { 62 | *error_str = 63 | apr_psprintf(pool, "pattern [%s] is not a valid regular expression: %s", regexp, *error_str); 64 | goto out; 65 | } 66 | 67 | if (_oidc_strlen(input) >= OIDC_PCRE_MAXCAPTURE - 1) { 68 | *error_str = 69 | apr_psprintf(pool, "string length (%d) is larger than the maximum allowed for pcre_subst (%d)", 70 | (int)_oidc_strlen(input), OIDC_PCRE_MAXCAPTURE - 1); 71 | goto out; 72 | } 73 | 74 | substituted = oidc_pcre_subst(pool, preg, input, (int)_oidc_strlen(input), replace); 75 | if (substituted == NULL) { 76 | *error_str = apr_psprintf( 77 | pool, "unknown error could not match string [%s] using pattern [%s] and replace matches in [%s]", 78 | input, regexp, replace); 79 | goto out; 80 | } 81 | 82 | *output = apr_pstrdup(pool, substituted); 83 | rc = TRUE; 84 | 85 | out: 86 | 87 | if (preg) 88 | oidc_pcre_free(preg); 89 | 90 | return rc; 91 | } 92 | 93 | /* 94 | * regexp match 95 | */ 96 | apr_byte_t oidc_util_regexp_first_match(apr_pool_t *pool, const char *input, const char *regexp, char **output, 97 | char **error_str) { 98 | apr_byte_t rv = FALSE; 99 | int rc = 0; 100 | 101 | struct oidc_pcre *preg = oidc_pcre_compile(pool, regexp, error_str); 102 | if (preg == NULL) { 103 | *error_str = 104 | apr_psprintf(pool, "pattern [%s] is not a valid regular expression: %s", regexp, *error_str); 105 | goto out; 106 | } 107 | 108 | if ((rc = oidc_pcre_exec(pool, preg, input, (int)_oidc_strlen(input), error_str)) < 0) 109 | goto out; 110 | 111 | if (output && (oidc_pcre_get_substring(pool, preg, input, rc, output, error_str) <= 0)) { 112 | *error_str = apr_psprintf(pool, "pcre_get_substring failed: %s", *error_str); 113 | goto out; 114 | } 115 | 116 | rv = TRUE; 117 | 118 | out: 119 | 120 | if (preg) 121 | oidc_pcre_free(preg); 122 | 123 | return rv; 124 | } 125 | 126 | /* 127 | * parse an Apache expression 128 | */ 129 | char *oidc_util_apr_expr_parse(cmd_parms *cmd, const char *str, oidc_apr_expr_t **expr, apr_byte_t result_is_str) { 130 | char *rv = NULL; 131 | if ((str == NULL) || (expr == NULL)) 132 | return NULL; 133 | *expr = apr_pcalloc(cmd->pool, sizeof(oidc_apr_expr_t)); 134 | (*expr)->str = apr_pstrdup(cmd->pool, str); 135 | const char *expr_err = NULL; 136 | unsigned int flags = AP_EXPR_FLAG_DONT_VARY & AP_EXPR_FLAG_RESTRICTED; 137 | if (result_is_str) 138 | flags += AP_EXPR_FLAG_STRING_RESULT; 139 | (*expr)->expr = ap_expr_parse_cmd(cmd, str, flags, &expr_err, NULL); 140 | if (expr_err != NULL) { 141 | rv = apr_pstrcat(cmd->temp_pool, "cannot parse expression: ", expr_err, NULL); 142 | *expr = NULL; 143 | } 144 | return rv; 145 | } 146 | 147 | /* 148 | * execute an Apache expression 149 | */ 150 | const char *oidc_util_apr_expr_exec(request_rec *r, const oidc_apr_expr_t *expr, apr_byte_t result_is_str) { 151 | const char *expr_result = NULL; 152 | if (expr == NULL) 153 | return NULL; 154 | const char *expr_err = NULL; 155 | if (result_is_str) { 156 | expr_result = ap_expr_str_exec(r, expr->expr, &expr_err); 157 | } else { 158 | expr_result = ap_expr_exec(r, expr->expr, &expr_err) ? "" : NULL; 159 | } 160 | if (expr_err) { 161 | oidc_error(r, "executing expression \"%s\" failed: %s", expr->str, expr_err); 162 | expr_result = NULL; 163 | } 164 | return expr_result; 165 | } 166 | -------------------------------------------------------------------------------- /src/util/file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "util/util.h" 44 | 45 | /* 46 | * read a file from a path on disk 47 | */ 48 | apr_byte_t oidc_util_file_read(request_rec *r, const char *path, apr_pool_t *pool, char **result) { 49 | apr_file_t *fd = NULL; 50 | apr_status_t rc = APR_SUCCESS; 51 | char s_err[128]; 52 | apr_finfo_t finfo; 53 | 54 | /* open the file if it exists */ 55 | if ((rc = apr_file_open(&fd, path, APR_FOPEN_READ | APR_FOPEN_BUFFERED, APR_OS_DEFAULT, r->pool)) != 56 | APR_SUCCESS) { 57 | oidc_warn(r, "no file found at: \"%s\" (%s)", path, apr_strerror(rc, s_err, sizeof(s_err))); 58 | return FALSE; 59 | } 60 | 61 | /* the file exists, now lock it */ 62 | apr_file_lock(fd, APR_FLOCK_EXCLUSIVE); 63 | 64 | /* move the read pointer to the very start of the cache file */ 65 | apr_off_t begin = 0; 66 | apr_file_seek(fd, APR_SET, &begin); 67 | 68 | /* get the file info so we know its size */ 69 | if ((rc = apr_file_info_get(&finfo, APR_FINFO_SIZE, fd)) != APR_SUCCESS) { 70 | oidc_error(r, "error calling apr_file_info_get on file: \"%s\" (%s)", path, 71 | apr_strerror(rc, s_err, sizeof(s_err))); 72 | goto error_close; 73 | } 74 | 75 | /* now that we have the size of the file, allocate a buffer that can contain its contents */ 76 | *result = apr_palloc(pool, finfo.size + 1); 77 | 78 | /* read the file in to the buffer */ 79 | apr_size_t bytes_read = 0; 80 | if ((rc = apr_file_read_full(fd, *result, finfo.size, &bytes_read)) != APR_SUCCESS) { 81 | oidc_error(r, "apr_file_read_full on (%s) returned an error: %s", path, 82 | apr_strerror(rc, s_err, sizeof(s_err))); 83 | goto error_close; 84 | } 85 | 86 | /* just to be sure, we set a \0 (we allocated space for it anyway) */ 87 | (*result)[bytes_read] = '\0'; 88 | 89 | /* check that we've got all of it */ 90 | if (bytes_read != finfo.size) { 91 | oidc_error(r, 92 | "apr_file_read_full on (%s) returned less bytes (%" APR_SIZE_T_FMT 93 | ") than expected: (%" APR_OFF_T_FMT ")", 94 | path, bytes_read, finfo.size); 95 | goto error_close; 96 | } 97 | 98 | /* we're done, unlock and close the file */ 99 | apr_file_unlock(fd); 100 | apr_file_close(fd); 101 | 102 | /* log successful content retrieval */ 103 | oidc_debug(r, "file read successfully \"%s\"", path); 104 | 105 | return TRUE; 106 | 107 | error_close: 108 | 109 | apr_file_unlock(fd); 110 | apr_file_close(fd); 111 | 112 | oidc_error(r, "return error"); 113 | 114 | return FALSE; 115 | } 116 | 117 | /* 118 | * write data to a file 119 | */ 120 | apr_byte_t oidc_util_file_write(request_rec *r, const char *path, const char *data) { 121 | 122 | apr_file_t *fd = NULL; 123 | apr_status_t rc = APR_SUCCESS; 124 | apr_size_t bytes_written = 0; 125 | char s_err[128]; 126 | 127 | /* try to open the metadata file for writing, creating it if it does not exist */ 128 | if ((rc = apr_file_open(&fd, path, (APR_FOPEN_WRITE | APR_FOPEN_CREATE | APR_FOPEN_TRUNCATE), APR_OS_DEFAULT, 129 | r->pool)) != APR_SUCCESS) { 130 | oidc_error(r, "file \"%s\" could not be opened (%s)", path, apr_strerror(rc, s_err, sizeof(s_err))); 131 | return FALSE; 132 | } 133 | 134 | /* lock the file and move the write pointer to the start of it */ 135 | apr_file_lock(fd, APR_FLOCK_EXCLUSIVE); 136 | apr_off_t begin = 0; 137 | apr_file_seek(fd, APR_SET, &begin); 138 | 139 | /* calculate the length of the data, which is a string length */ 140 | apr_size_t len = _oidc_strlen(data); 141 | 142 | /* (blocking) write the number of bytes in the buffer */ 143 | rc = apr_file_write_full(fd, data, len, &bytes_written); 144 | 145 | /* check for a system error */ 146 | if (rc != APR_SUCCESS) { 147 | oidc_error(r, "could not write to: \"%s\" (%s)", path, apr_strerror(rc, s_err, sizeof(s_err))); 148 | return FALSE; 149 | } 150 | 151 | /* check that all bytes from the header were written */ 152 | if (bytes_written != len) { 153 | oidc_error(r, 154 | "could not write enough bytes to: \"%s\", bytes_written (%" APR_SIZE_T_FMT 155 | ") != len (%" APR_SIZE_T_FMT ")", 156 | path, bytes_written, len); 157 | return FALSE; 158 | } 159 | 160 | /* unlock and close the written file */ 161 | apr_file_unlock(fd); 162 | apr_file_close(fd); 163 | 164 | oidc_debug(r, "file \"%s\" written; number of bytes (%" APR_SIZE_T_FMT ")", path, len); 165 | 166 | return TRUE; 167 | } 168 | -------------------------------------------------------------------------------- /src/proto/discovery.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "cfg/dir.h" 44 | #include "cfg/parse.h" 45 | #include "mod_auth_openidc.h" 46 | #include "proto/proto.h" 47 | #include "util/util.h" 48 | 49 | /* 50 | * based on a resource perform OpenID Connect Provider Issuer Discovery to find out the issuer and obtain and store its 51 | * metadata 52 | */ 53 | static apr_byte_t oidc_proto_webfinger_discovery(request_rec *r, oidc_cfg_t *cfg, const char *resource, 54 | const char *domain, char **issuer) { 55 | 56 | const char *url = apr_psprintf(r->pool, "https://%s/.well-known/webfinger", domain); 57 | 58 | apr_table_t *params = apr_table_make(r->pool, 1); 59 | apr_table_setn(params, "resource", resource); 60 | apr_table_setn(params, "rel", "http://openid.net/specs/connect/1.0/issuer"); 61 | 62 | char *response = NULL; 63 | if (oidc_http_get(r, url, params, NULL, NULL, NULL, 64 | oidc_cfg_provider_ssl_validate_server_get(oidc_cfg_provider_get(cfg)), &response, NULL, NULL, 65 | oidc_cfg_http_timeout_short_get(cfg), oidc_cfg_outgoing_proxy_get(cfg), 66 | oidc_cfg_dir_pass_cookies_get(r), NULL, NULL, NULL) == FALSE) { 67 | /* errors will have been logged by now */ 68 | return FALSE; 69 | } 70 | 71 | /* decode and see if it is not an error response somehow */ 72 | json_t *j_response = NULL; 73 | if (oidc_util_json_decode_and_check_error(r, response, &j_response) == FALSE) 74 | return FALSE; 75 | 76 | /* get the links parameter */ 77 | json_t *j_links = json_object_get(j_response, "links"); 78 | if ((j_links == NULL) || (!json_is_array(j_links))) { 79 | oidc_error(r, "response JSON object did not contain a \"links\" array"); 80 | json_decref(j_response); 81 | return FALSE; 82 | } 83 | 84 | /* get the one-and-only object in the "links" array */ 85 | json_t *j_object = json_array_get(j_links, 0); 86 | if ((j_object == NULL) || (!json_is_object(j_object))) { 87 | oidc_error( 88 | r, 89 | "response JSON object did not contain a JSON object as the first element in the \"links\" array"); 90 | json_decref(j_response); 91 | return FALSE; 92 | } 93 | 94 | /* get the href from that object, which is the issuer value */ 95 | json_t *j_href = json_object_get(j_object, "href"); 96 | if ((j_href == NULL) || (!json_is_string(j_href))) { 97 | oidc_error( 98 | r, "response JSON object did not contain a \"href\" element in the first \"links\" array object"); 99 | json_decref(j_response); 100 | return FALSE; 101 | } 102 | 103 | /* check that the link is on secure HTTPs */ 104 | if (oidc_cfg_parse_is_valid_url(r->pool, json_string_value(j_href), "https") != NULL) { 105 | oidc_error(r, "response JSON object contains an \"href\" value that is not a valid \"https\" URL: %s", 106 | json_string_value(j_href)); 107 | json_decref(j_response); 108 | return FALSE; 109 | } 110 | 111 | *issuer = apr_pstrdup(r->pool, json_string_value(j_href)); 112 | 113 | oidc_debug(r, "returning issuer \"%s\" for resource \"%s\" after doing successful webfinger-based discovery", 114 | *issuer, resource); 115 | 116 | json_decref(j_response); 117 | 118 | return TRUE; 119 | } 120 | 121 | /* 122 | * based on an account name, perform OpenID Connect Provider Issuer Discovery to find out the issuer and obtain and 123 | * store its metadata 124 | */ 125 | apr_byte_t oidc_proto_discovery_account_based(request_rec *r, oidc_cfg_t *cfg, const char *acct, char **issuer) { 126 | 127 | // TODO: maybe show intermediate/progress screen "discovering..." 128 | 129 | oidc_debug(r, "enter, acct=%s", acct); 130 | 131 | const char *resource = apr_psprintf(r->pool, "acct:%s", acct); 132 | const char *domain = strrchr(acct, OIDC_CHAR_AT); 133 | if (domain == NULL) { 134 | oidc_error(r, "invalid account name"); 135 | return FALSE; 136 | } 137 | domain++; 138 | 139 | return oidc_proto_webfinger_discovery(r, cfg, resource, domain, issuer); 140 | } 141 | 142 | /* 143 | * based on user identifier URL, perform OpenID Connect Provider Issuer Discovery to find out the issuer and obtain and 144 | * store its metadata 145 | */ 146 | apr_byte_t oidc_proto_discovery_url_based(request_rec *r, oidc_cfg_t *cfg, const char *url, char **issuer) { 147 | 148 | oidc_debug(r, "enter, url=%s", url); 149 | 150 | apr_uri_t uri; 151 | apr_uri_parse(r->pool, url, &uri); 152 | 153 | char *domain = uri.hostname; 154 | if (uri.port_str != NULL) 155 | domain = apr_psprintf(r->pool, "%s:%s", domain, uri.port_str); 156 | 157 | return oidc_proto_webfinger_discovery(r, cfg, url, domain, issuer); 158 | } 159 | -------------------------------------------------------------------------------- /src/handle/content.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "handle/handle.h" 44 | #include "metrics.h" 45 | #include "mod_auth_openidc.h" 46 | #include "util/util.h" 47 | 48 | /* 49 | * handle content generating requests 50 | */ 51 | int oidc_content_handler(request_rec *r) { 52 | oidc_cfg_t *c = ap_get_module_config(r->server->module_config, &auth_openidc_module); 53 | int rc = DECLINED; 54 | /* track if the session needs to be updated/saved into the cache */ 55 | apr_byte_t needs_save = FALSE; 56 | oidc_session_t *session = NULL; 57 | 58 | if ((r->parsed_uri.path != NULL) && (oidc_cfg_metrics_path_get(c) != NULL)) 59 | if (_oidc_strcmp(r->parsed_uri.path, oidc_cfg_metrics_path_get(c)) == 0) 60 | return oidc_metrics_handle_request(r); 61 | 62 | if (oidc_enabled(r, c) == FALSE) { 63 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_DECLINED); 64 | return DECLINED; 65 | } 66 | 67 | if (oidc_util_url_matches_redirect_uri(r, c) == TRUE) { 68 | 69 | /* requests to the redirect URI are handled and finished here */ 70 | rc = OK; 71 | 72 | /* NB: check HTTP/HTML request before info (and others) so Logout HTML is processed if there's no 73 | * session (anymore) */ 74 | if (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_HTTP) != NULL) { 75 | 76 | /* HTTP response has been generated and stored in the request state */ 77 | rc = oidc_util_http_content_send(r); 78 | 79 | } else if (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_HTML) != NULL) { 80 | 81 | /* HTML body has been generated and stored in the request state */ 82 | rc = oidc_util_html_content_send(r); 83 | 84 | } else if (oidc_util_url_has_parameter(r, OIDC_REDIRECT_URI_REQUEST_INFO)) { 85 | 86 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_INFO); 87 | 88 | /* see if a session was retained in the request state */ 89 | apr_pool_userdata_get((void **)&session, OIDC_USERDATA_SESSION, r->pool); 90 | 91 | /* if no retained session was found, load it from the cache or create a new one*/ 92 | if (session == NULL) 93 | oidc_session_load(r, &session); 94 | 95 | /* 96 | * see if the request state indicates that the (retained) 97 | * session was modified and needs to be updated in the cache 98 | */ 99 | needs_save = (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_SAVE) != NULL); 100 | 101 | /* handle request for session info */ 102 | rc = oidc_info_request(r, c, session, needs_save); 103 | 104 | /* free resources allocated for the session */ 105 | oidc_session_free(r, session); 106 | 107 | } else if (oidc_util_url_has_parameter(r, OIDC_REDIRECT_URI_REQUEST_DPOP)) { 108 | 109 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_DPOP); 110 | 111 | /* handle request to create a DPoP proof */ 112 | rc = oidc_dpop_request(r, c); 113 | 114 | } else if (oidc_util_url_has_parameter(r, OIDC_REDIRECT_URI_REQUEST_JWKS)) { 115 | 116 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_JWKS); 117 | 118 | /* handle JWKs request */ 119 | rc = oidc_jwks_request(r, c); 120 | 121 | } else { 122 | 123 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_UNKNOWN); 124 | } 125 | 126 | } else if (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_DISCOVERY) != NULL) { 127 | 128 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_DISCOVERY); 129 | 130 | /* discovery may result in a 200 HTML page or a redirect to an external URL */ 131 | rc = oidc_discovery_request(r, c); 132 | 133 | } else if (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_AUTHN_POST) != NULL) { 134 | 135 | /* sending POST authentication request */ 136 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_AUTHN_POST); 137 | 138 | /* HTML body has been generated and stored in the request state */ 139 | rc = oidc_util_html_content_send(r); 140 | 141 | } else if (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_AUTHN_PRESERVE) != NULL) { 142 | 143 | /* sending POST preserve request */ 144 | OIDC_METRICS_COUNTER_INC(r, c, OM_CONTENT_REQUEST_POST_PRESERVE); 145 | 146 | /* Javascript for HTML head has been generated and stored in the request state */ 147 | rc = oidc_util_html_content_send(r); 148 | 149 | } else if (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_HTTP) != NULL) { 150 | 151 | /* HTTP response has been generated and stored in the request state */ 152 | rc = oidc_util_http_content_send(r); 153 | 154 | } else if (oidc_request_state_get(r, OIDC_REQUEST_STATE_KEY_HTML) != NULL) { 155 | 156 | /* HTML body has been generated and stored in the request state */ 157 | rc = oidc_util_html_content_send(r); 158 | 159 | } /* else: an authenticated request for which content is produced downstream */ 160 | 161 | return rc; 162 | } 163 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | AC_INIT([mod_auth_openidc],[2.4.19.1dev],[hans.zandbelt@openidc.com]) 2 | 3 | AC_SUBST(NAMEVER, AC_PACKAGE_TARNAME()-AC_PACKAGE_VERSION()) 4 | 5 | AM_INIT_AUTOMAKE([-Wall -Werror foreign subdir-objects]) 6 | 7 | AC_CONFIG_HEADERS([src/config.h]) 8 | AC_CONFIG_MACRO_DIR([m4]) 9 | 10 | AC_PROG_CC 11 | AM_PROG_CC_C_O 12 | AM_PROG_AR 13 | LT_INIT([dlopen]) 14 | 15 | AX_CODE_COVERAGE 16 | 17 | # Checks for apxs. 18 | AC_ARG_WITH([apxs], 19 | [AS_HELP_STRING([--with-apxs=PATH/NAME],[path to the apxs binary for Apache [apxs]])], 20 | [AC_SUBST(APXS, $with_apxs)], 21 | [AC_PATH_PROGS(APXS, [apxs apxs2],,)]) 22 | 23 | if test ! -x "$APXS"; then 24 | # $APXS isn't a executable file. 25 | AC_MSG_ERROR([ 26 | Could not find apxs. Please specify the path to apxs 27 | using the --with-apxs=/full/path/to/apxs option. 28 | The executable may also be named 'apxs2'. 29 | ]) 30 | fi 31 | 32 | APXS_CFLAGS=`${APXS} -q CFLAGS 2> /dev/null` 33 | APXS_CPPFLAGS=`${APXS} -q CPPFLAGS 2> /dev/null` 34 | APXS_LDFLAGS=`${APXS} -q LDFLAGS 2> /dev/null` 35 | APXS_LIBS=`${APXS} -q LIBS 2> /dev/null` 36 | APXS_LIBEXECDIR=`${APXS} -q LIBEXECDIR 2> /dev/null` 37 | APXS_INCLUDEDIR=`${APXS} -q INCLUDEDIR 2> /dev/null` 38 | APXS_INCLUDES="-I${APXS_INCLUDEDIR}" 39 | 40 | PKG_CHECK_MODULES(APR, [apr-1, apr-util-1]) 41 | 42 | # Apache libraries. 43 | APACHE_MODULEDIR="${APXS_LIBEXECDIR}" 44 | APACHE_INCLUDES="${APXS_INCLUDES} ${APR_INCLUDES}" 45 | APACHE_CFLAGS="${APXS_CFLAGS} ${APR_CFLAGS} ${APACHE_INCLUDES}" 46 | APACHE_CPPFLAGS="${APXS_CPPFLAGS} ${APR_CPPFLAGS} ${APACHE_INCLUDES}" 47 | APACHE_LDFLAGS="${APXS_LDFLAGS} ${APR_LDFLAGS}" 48 | APACHE_LIBS="${APXS_LIBS} ${APR_LIBS}" 49 | 50 | AC_SUBST(APACHE_MODULEDIR) 51 | AC_SUBST(APACHE_INCLUDES) 52 | AC_SUBST(APACHE_CFLAGS) 53 | AC_SUBST(APACHE_CPPFLAGS) 54 | AC_SUBST(APACHE_LDFLAGS) 55 | AC_SUBST(APACHE_LIBS) 56 | 57 | # We need the curl library for HTTP callouts. 58 | PKG_CHECK_MODULES(CURL, libcurl) 59 | AC_SUBST(CURL_CFLAGS) 60 | AC_SUBST(CURL_LIBS) 61 | 62 | # We need OpenSSL for crypto and HTTPS callouts. 63 | PKG_CHECK_MODULES(OPENSSL, openssl) 64 | AC_SUBST(OPENSSL_CFLAGS) 65 | AC_SUBST(OPENSSL_LIBS) 66 | 67 | # older versions of libapr may not have memcache support 68 | old_CPPFLAGS=$CPPFLAGS 69 | CPPFLAGS="${APACHE_CPPFLAGS} ${APACHE_CFLAGS} $CPPFLAGS" 70 | AC_CHECK_HEADER([apr_memcache.h], [HAVE_MEMCACHE=1], [HAVE_MEMCACHE=0]) 71 | AM_CONDITIONAL(HAVE_MEMCACHE,[test x"$HAVE_MEMCACHE" = "x1"]) 72 | CPPFLAGS=$old_CPPFLAGS 73 | 74 | # We need Jansson for JSON parsing. 75 | PKG_CHECK_MODULES(JANSSON, jansson) 76 | AC_SUBST(JANSSON_CFLAGS) 77 | AC_SUBST(JANSSON_LIBS) 78 | 79 | # cjose 80 | PKG_CHECK_MODULES(CJOSE, cjose) 81 | AC_SUBST(CJOSE_CFLAGS) 82 | AC_SUBST(CJOSE_LIBS) 83 | 84 | # PCRE 85 | PKG_CHECK_MODULES([PCRE2], libpcre2-8, [ 86 | PCRE_CFLAGS="$PCRE2_CFLAGS" 87 | PCRE_LIBS="$PCRE2_LIBS" 88 | AC_DEFINE([HAVE_LIBPCRE2], [1], [Define if libpcre2 is available.]) 89 | enable_pcre2=yes 90 | ], [ 91 | AC_CHECK_HEADER(pcre2.h, [ 92 | AC_CHECK_LIB(pcre2-8, pcre2_compile_8, [ 93 | PCRE_LIBS="-lpcre2-8" 94 | AC_DEFINE([HAVE_LIBPCRE2], 1, [Define if libpcre2 is available.]) 95 | enable_pcre2=yes 96 | ]) 97 | ]) 98 | ]) 99 | 100 | AS_IF([test "X$enable_pcre2" != "Xyes"],[ 101 | PKG_CHECK_MODULES([PCRE], libpcre, [ 102 | CFLAGS="$PCRE_CFLAGS $CFLAGS" 103 | AC_CHECK_HEADER(pcre.h, [ 104 | LIBS="$PCRE_LIBS $LIBS" 105 | AC_DEFINE([HAVE_LIBPCRE], [1], [Define if libpcre is available.]) 106 | enable_pcre=yes 107 | ]) 108 | ], [ 109 | AC_CHECK_HEADER(pcre.h, [ 110 | AC_CHECK_LIB(pcre, pcre_compile, [ 111 | PCRE_LIBS="-lpcre" 112 | AC_DEFINE([HAVE_LIBPCRE], 1, [Define if libpcre is available.]) 113 | ]) 114 | ]) 115 | ]) 116 | ]) 117 | 118 | AS_IF([test "X$enable_pcre2" = Xyes], [PCRE_INFO="yes, via libpcre2"], [test "X$enable_pcre" = Xyes], [PCRE_INFO="yes, via libpcre"], [PCRE_INFO=no]) 119 | 120 | AC_SUBST(PCRE_CFLAGS) 121 | AC_SUBST(PCRE_LIBS) 122 | 123 | AC_ARG_WITH(brotli, 124 | AS_HELP_STRING([--with-brotli], [enable brotli compression support [default=no]]), 125 | ac_brotli=$withval, ac_brotli=no) 126 | if test x$ac_brotli != xno; then 127 | PKG_CHECK_MODULES(LIBBROTLIENC, [libbrotlienc >= 1.0.0], [with_libbrotlienc=yes], [with_libbrotlienc=no]) 128 | PKG_CHECK_MODULES(LIBBROTLIDEC, [libbrotlidec >= 1.0.0], [with_libbrotlidec=yes], [with_libbrotlidec=no]) 129 | fi 130 | AM_CONDITIONAL(HAVE_LIBBROTLI, [test "${with_libbrotlienc}" == "yes" && test "${with_libbrotlidec}" == "yes"]) 131 | AC_SUBST([LIBBROTLIENC_CFLAGS]) 132 | AC_SUBST([LIBBROTLIDEC_CFLAGS]) 133 | AC_SUBST([LIBBROTLIENC_LIBS]) 134 | AC_SUBST([LIBBROTLIDEC_LIBS]) 135 | 136 | if test "${with_libbrotlienc}" != "yes" || test "${with_libbrotlidec}" != "yes"; then 137 | PKG_CHECK_MODULES([ZLIB], [zlib], [HAVE_LIBZ=1], [HAVE_LIBZ=0]) 138 | fi 139 | AM_CONDITIONAL(HAVE_LIBZ, [test x"$HAVE_LIBZ" = "x1"]) 140 | AC_SUBST([ZLIB_CFLAGS]) 141 | AC_SUBST([ZLIB_LIBS]) 142 | 143 | # Redis 144 | AC_ARG_WITH([hiredis], 145 | [AS_HELP_STRING([--with-hiredis], 146 | [support Redis @<:@default=check@:>@])], 147 | [], 148 | [with_hiredis=yes]) 149 | AS_CASE(["$with_hiredis"], 150 | [yes], [ 151 | if test "$HIREDIS_LIBS" == ""; then PKG_CHECK_MODULES([HIREDIS], [hiredis], [HAVE_LIBHIREDIS=1], [HAVE_LIBHIREDIS=0]) ; else [HAVE_LIBHIREDIS=1] ; fi 152 | ], 153 | [no], [HAVE_LIBHIREDIS=0], 154 | [PKG_CHECK_MODULES([HIREDIS], [hiredis], [HAVE_LIBHIREDIS=1], [HAVE_LIBHIREDIS=0])]) 155 | AM_CONDITIONAL(HAVE_LIBHIREDIS, [test x"$HAVE_LIBHIREDIS" = "x1"]) 156 | AC_SUBST(HIREDIS_CFLAGS) 157 | AC_SUBST(HIREDIS_LIBS) 158 | 159 | # JQ 160 | HAVE_LIBJQ=0 161 | 162 | AC_ARG_WITH([jq], AS_HELP_STRING([--with-jq=PATH], [location of libjq development headers]),) 163 | 164 | if test -n "$with_jq" 165 | then 166 | if test "$JQ_CFLAGS" == ""; then 167 | if test "$with_jq" == "yes"; then 168 | JQ_CFLAGS="-I/usr/include" 169 | else 170 | JQ_CFLAGS="-I$with_jq/include" 171 | fi 172 | fi 173 | if test "$JQ_LIBS" == ""; then 174 | if test "$with_jq" == "yes"; then 175 | JQ_LIBS="-L/usr/lib -ljq" 176 | else 177 | JQ_LIBS="-L$with_jq/lib -ljq" 178 | fi 179 | fi 180 | 181 | CPPFLAGS="$JQ_CFLAGS $CPPFLAGS" 182 | AC_CHECK_HEADER([jq.h], [HAVE_LIBJQ=1], [HAVE_LIBJQ=0]) 183 | 184 | LDFLAGS="$JQ_LIBS $LDFLAGS" 185 | AC_CHECK_LIB([jq], [jq_init], [HAVE_LIBJQ=1], [HAVE_LIBJQ=0]) 186 | if test "x$have_jq" = "x0" ; then 187 | AC_MSG_WARN("cannot find library for -ljq.") 188 | fi 189 | fi 190 | 191 | AM_CONDITIONAL(HAVE_LIBJQ, [test x"$HAVE_LIBJQ" = "x1"]) 192 | AC_SUBST(JQ_CFLAGS) 193 | AC_SUBST(JQ_LIBS) 194 | 195 | # check 196 | PKG_CHECK_MODULES([CHECK], 197 | [check >= 0.9.4], 198 | [have_check="yes"], 199 | [AC_MSG_WARN([Check not found; cannot run unit tests!]); 200 | [have_check="no"] 201 | ]) 202 | AM_CONDITIONAL(HAVE_CHECK, [test x"$have_check" = "xyes"]) 203 | AC_SUBST(CHECK_CFLAGS) 204 | AC_SUBST(CHECK_LIBS) 205 | 206 | # Create Makefile from Makefile.in 207 | AC_CONFIG_FILES([ 208 | Makefile 209 | src/Makefile 210 | test/Makefile 211 | ]) 212 | AC_OUTPUT 213 | -------------------------------------------------------------------------------- /test/util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | * 42 | **************************************************************************/ 43 | 44 | #include "util.h" 45 | #include "cfg/cfg_int.h" 46 | #include "cfg/dir.h" 47 | #include 48 | 49 | static apr_pool_t *pool = NULL; 50 | static request_rec *request = NULL; 51 | 52 | static request_rec *oidc_test_request_init(apr_pool_t *pool) { 53 | const unsigned int kIdx = 0; 54 | const unsigned int kEls = kIdx + 1; 55 | request_rec *request = (request_rec *)apr_pcalloc(pool, sizeof(request_rec)); 56 | 57 | apr_pool_create(&request->pool, pool); 58 | 59 | request->subprocess_env = apr_table_make(request->pool, 0); 60 | 61 | request->headers_in = apr_table_make(request->pool, 0); 62 | request->headers_out = apr_table_make(request->pool, 0); 63 | request->err_headers_out = apr_table_make(request->pool, 0); 64 | 65 | apr_table_set(request->headers_in, "Host", "www.example.com"); 66 | apr_table_set(request->headers_in, "OIDC_foo", "some-value"); 67 | apr_table_set(request->headers_in, "Cookie", 68 | "foo=bar; " 69 | "mod_auth_openidc_session" 70 | "=0123456789abcdef; baz=zot"); 71 | 72 | request->server = apr_pcalloc(pool, sizeof(struct server_rec)); 73 | request->server->process = apr_pcalloc(pool, sizeof(struct process_rec)); 74 | apr_pool_create(&request->server->process->pool, pool); 75 | apr_pool_create(&request->server->process->pconf, pool); 76 | request->connection = apr_pcalloc(pool, sizeof(struct conn_rec)); 77 | request->connection->bucket_alloc = apr_bucket_alloc_create(pool); 78 | request->connection->local_addr = apr_pcalloc(pool, sizeof(apr_sockaddr_t)); 79 | 80 | apr_pool_userdata_set("https", "scheme", NULL, request->pool); 81 | request->server->server_hostname = "www.example.com"; 82 | request->connection->local_addr->port = 4433; 83 | request->unparsed_uri = "/bla?foo=bar¶m1=value1"; 84 | request->args = "foo=bar¶m1=value1"; 85 | apr_uri_parse(request->pool, "https://www.example.com/bla?foo=bar¶m1=value1", &request->parsed_uri); 86 | 87 | auth_openidc_module.module_index = kIdx; 88 | oidc_cfg_t *cfg = oidc_cfg_server_create(request->server->process->pconf, request->server); 89 | 90 | oidc_cfg_provider_issuer_set(request->server->process->pconf, oidc_cfg_provider_get(cfg), 91 | "https://idp.example.com"); 92 | oidc_cfg_provider_authorization_endpoint_url_set(request->server->process->pconf, oidc_cfg_provider_get(cfg), 93 | "https://idp.example.com/authorize"); 94 | oidc_cfg_provider_client_id_set(request->server->process->pconf, oidc_cfg_provider_get(cfg), "client_id"); 95 | 96 | cfg->redirect_uri = "https://www.example.com/protected/"; 97 | 98 | oidc_dir_cfg_t *d_cfg = oidc_cfg_dir_config_create(request->server->process->pconf, NULL); 99 | 100 | // coverity[suspicious_sizeof] 101 | request->server->module_config = apr_pcalloc(request->server->process->pconf, sizeof(void *) * kEls); 102 | // coverity[suspicious_sizeof] 103 | request->per_dir_config = apr_pcalloc(request->server->process->pconf, sizeof(void *) * kEls); 104 | ap_set_module_config(request->server->module_config, &auth_openidc_module, cfg); 105 | ap_set_module_config(request->per_dir_config, &auth_openidc_module, d_cfg); 106 | 107 | // TODO: 108 | cfg->public_keys = apr_array_make(request->server->process->pconf, 1, sizeof(const char *)); 109 | cfg->private_keys = apr_array_make(request->server->process->pconf, 1, sizeof(const char *)); 110 | 111 | cfg->crypto_passphrase.secret1 = "12345678901234567890123456789012"; 112 | cfg->cache.impl = &oidc_cache_shm; 113 | cfg->cache.cfg = NULL; 114 | cfg->cache.shm_size_max = 500; 115 | cfg->cache.shm_entry_size_max = 16384 + 255 + 17; 116 | cfg->cache.encrypt = 1; 117 | if (cfg->cache.impl->post_config(request->server->process->pconf, request->server) != OK) { 118 | fprintf(stderr, "cfg->cache.impl->post_config failed!\n"); 119 | exit(-1); 120 | } 121 | 122 | return request; 123 | } 124 | 125 | void oidc_test_setup(void) { 126 | apr_initialize(); 127 | oidc_pre_config_init(); 128 | apr_pool_create(&pool, NULL); 129 | request = oidc_test_request_init(pool); 130 | } 131 | 132 | void oidc_test_teardown(void) { 133 | EVP_cleanup(); 134 | apr_terminate(); 135 | } 136 | 137 | apr_pool_t *oidc_test_pool_get() { 138 | return pool; 139 | } 140 | 141 | request_rec *oidc_test_request_get() { 142 | return request; 143 | } 144 | 145 | oidc_cfg_t *oidc_test_cfg_get() { 146 | return (oidc_cfg_t *)ap_get_module_config(request->server->module_config, &auth_openidc_module); 147 | } 148 | 149 | cmd_parms *oidc_test_cmd_get(const char *primitive) { 150 | request_rec *r = oidc_test_request_get(); 151 | cmd_parms *cmd = apr_pcalloc(r->pool, sizeof(cmd_parms)); 152 | cmd->server = r->server; 153 | cmd->pool = r->pool; 154 | cmd->temp_pool = r->pool; 155 | cmd->directive = apr_pcalloc(cmd->pool, sizeof(ap_directive_t)); 156 | cmd->directive->directive = primitive; 157 | return cmd; 158 | } 159 | -------------------------------------------------------------------------------- /src/const.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * Copyright (C) 2013-2017 Ping Identity Corporation 23 | * All rights reserved. 24 | * 25 | * DISCLAIMER OF WARRANTIES: 26 | * 27 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 28 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 29 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 30 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 31 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 32 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 33 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 34 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 35 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 36 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 37 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 38 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | * 41 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 42 | */ 43 | 44 | #ifndef _MOD_AUTH_OPENIDC_CONST_H_ 45 | #define _MOD_AUTH_OPENIDC_CONST_H_ 46 | 47 | #ifdef HAVE_CONFIG_H 48 | #include "config.h" 49 | #undef PACKAGE_NAME 50 | #undef PACKAGE_STRING 51 | #undef PACKAGE_TARNAME 52 | #undef PACKAGE_VERSION 53 | #undef PACKAGE_BUGREPORT 54 | #endif 55 | 56 | #include 57 | #define __STDC_WANT_LIB_EXT1__ 1 58 | #include 59 | 60 | #include 61 | 62 | // clang-format off 63 | 64 | #include 65 | #include 66 | 67 | // clang-format on 68 | 69 | #ifdef __STDC_LIB_EXT1__ 70 | #define _oidc_memset(b, c, __len) memset_s(b, __len, c, __len) 71 | #define _oidc_memcpy(__dst, __src, __n) memcpy_s(__dst, __src, __n) 72 | #define _oidc_strcpy(__dst, __src) strcpy_s(__dst, __src) 73 | #define _oidc_strncpy(__dst, __src, __n) strncpy_s(__dst, __src, __n) 74 | #else 75 | #define _oidc_memset(b, c, __len) memset(b, c, __len) 76 | #define _oidc_memcpy(__dst, __src, __n) memcpy(__dst, __src, __n) 77 | #define _oidc_strcpy(__dst, __src) strcpy(__dst, __src) 78 | #define _oidc_strncpy(__dst, __src, __n) strncpy(__dst, __src, __n) 79 | #endif 80 | 81 | static inline size_t _oidc_strlen(const char *s) { 82 | return (s ? strlen(s) : 0); 83 | } 84 | static inline int _oidc_strcmp(const char *a, const char *b) { 85 | return ((a && b) ? apr_strnatcmp(a, b) : -1); 86 | } 87 | static inline int _oidc_strnatcasecmp(const char *a, const char *b) { 88 | return ((a && b) ? apr_strnatcasecmp(a, b) : -1); 89 | } 90 | static inline int _oidc_strncmp(const char *a, const char *b, size_t n) { 91 | return ((a && b) ? strncmp(a, b, n) : -1); 92 | } 93 | static inline char *_oidc_strstr(const char *a, const char *b) { 94 | return ((a && b) ? (char *)strstr(a, b) : NULL); 95 | } 96 | static inline apr_time_t _oidc_str_to_time(const char *s, const apr_time_t default_value) { 97 | apr_time_t v = default_value; 98 | if (s) 99 | sscanf(s, "%" APR_TIME_T_FMT, &v); 100 | return v; 101 | } 102 | static inline int _oidc_str_to_int(const char *s, const int default_value) { 103 | int v = default_value; 104 | if (s) 105 | v = strtol(s, NULL, 10); 106 | return v; 107 | } 108 | 109 | #ifdef WIN32 110 | #define snprintf _snprintf 111 | #endif 112 | 113 | #ifndef OIDC_DEBUG 114 | #define OIDC_DEBUG APLOG_DEBUG 115 | #endif 116 | 117 | #ifndef APLOG_TRACE1 118 | #define APLOG_TRACE1 APLOG_DEBUG 119 | #endif 120 | 121 | #ifndef apr_uintptr_t 122 | #define apr_uintptr_t apr_uint64_t 123 | #endif 124 | 125 | #ifndef APR_UINT32_MAX 126 | #define APR_UINT32_MAX UINT32_MAX 127 | #endif 128 | 129 | #ifndef APR_INT64_MAX 130 | #define APR_INT64_MAX INT64_MAX 131 | #endif 132 | 133 | #ifndef apr_time_from_msec 134 | #define apr_time_from_msec(msec) ((apr_time_t)(msec) * 1000) 135 | #endif 136 | 137 | #define oidc_log(r, level, fmt, ...) \ 138 | ap_log_rerror(APLOG_MARK, level, 0, r, "%s: %s", __FUNCTION__, apr_psprintf(r->pool, fmt, ##__VA_ARGS__)) 139 | #define oidc_slog(s, level, fmt, ...) \ 140 | ap_log_error(APLOG_MARK, level, 0, s, "%s: %s", __FUNCTION__, \ 141 | apr_psprintf(s->process->pconf, fmt, ##__VA_ARGS__)) 142 | 143 | #define oidc_debug(r, fmt, ...) oidc_log(r, OIDC_DEBUG, fmt, ##__VA_ARGS__) 144 | #define oidc_warn(r, fmt, ...) oidc_log(r, APLOG_WARNING, fmt, ##__VA_ARGS__) 145 | #define oidc_info(r, fmt, ...) oidc_log(r, APLOG_INFO, fmt, ##__VA_ARGS__) 146 | #define oidc_error(r, fmt, ...) oidc_log(r, APLOG_ERR, fmt, ##__VA_ARGS__) 147 | 148 | #define oidc_sdebug(s, fmt, ...) oidc_slog(s, OIDC_DEBUG, fmt, ##__VA_ARGS__) 149 | #define oidc_swarn(s, fmt, ...) oidc_slog(s, APLOG_WARNING, fmt, ##__VA_ARGS__) 150 | #define oidc_serror(s, fmt, ...) oidc_slog(s, APLOG_ERR, fmt, ##__VA_ARGS__) 151 | 152 | #ifndef NAMEVER 153 | #define NAMEVERSION "mod_auth_openidc-0.0.0" 154 | #else 155 | #define STRINGIFY(x) #x 156 | #define TOSTRING(x) STRINGIFY(x) 157 | #define NAMEVERSION TOSTRING(NAMEVER) 158 | #endif 159 | 160 | #define OIDC_CHAR_EQUAL '=' 161 | #define OIDC_CHAR_COLON ':' 162 | #define OIDC_CHAR_TILDE '~' 163 | #define OIDC_CHAR_SPACE ' ' 164 | #define OIDC_CHAR_COMMA ',' 165 | #define OIDC_CHAR_QUERY '?' 166 | #define OIDC_CHAR_DOT '.' 167 | #define OIDC_CHAR_AT '@' 168 | #define OIDC_CHAR_FORWARD_SLASH '/' 169 | #define OIDC_CHAR_PIPE '|' 170 | #define OIDC_CHAR_AMP '&' 171 | #define OIDC_CHAR_SEMI_COLON ';' 172 | 173 | #define OIDC_STR_SPACE " " 174 | #define OIDC_STR_EQUAL "=" 175 | #define OIDC_STR_AMP "&" 176 | #define OIDC_STR_QUERY "?" 177 | #define OIDC_STR_COLON ":" 178 | #define OIDC_STR_SEMI_COLON ";" 179 | #define OIDC_STR_FORWARD_SLASH "/" 180 | #define OIDC_STR_AT "@" 181 | #define OIDC_STR_COMMA "," 182 | #define OIDC_STR_HASH "#" 183 | 184 | #endif /* _MOD_AUTH_OPENIDC_CONST_H_ */ 185 | -------------------------------------------------------------------------------- /src/session.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_SESSION_H_ 44 | #define _MOD_AUTH_OPENIDC_SESSION_H_ 45 | 46 | #include "cfg/cfg.h" 47 | #include 48 | 49 | typedef struct { 50 | char *uuid; /* unique id */ 51 | char *remote_user; /* user who owns this particular session */ 52 | json_t *state; /* the state for this session, encoded in a JSON object */ 53 | apr_time_t expiry; /* if > 0, the time of expiry of this session */ 54 | char *sid; 55 | } oidc_session_t; 56 | 57 | /* value that indicates to use server-side cache based session tracking */ 58 | #define OIDC_SESSION_TYPE_SERVER_CACHE 0 59 | /* value that indicates to use client cookie based session tracking */ 60 | #define OIDC_SESSION_TYPE_CLIENT_COOKIE 1 61 | 62 | apr_byte_t oidc_session_load(request_rec *r, oidc_session_t **z); 63 | apr_byte_t oidc_session_save(request_rec *r, oidc_session_t *z, apr_byte_t first_time); 64 | apr_byte_t oidc_session_kill(request_rec *r, oidc_session_t *z); 65 | apr_byte_t oidc_session_free(request_rec *r, oidc_session_t *z); 66 | apr_byte_t oidc_session_extract(request_rec *r, oidc_session_t *z); 67 | apr_byte_t oidc_session_load_cache_by_uuid(request_rec *r, oidc_cfg_t *c, const char *uuid, oidc_session_t *z); 68 | void oidc_session_id_new(request_rec *r, oidc_session_t *z); 69 | 70 | void oidc_session_set_userinfo_jwt(request_rec *r, oidc_session_t *z, const char *userinfo_jwt); 71 | const char *oidc_session_get_userinfo_jwt(request_rec *r, oidc_session_t *z); 72 | void oidc_session_set_userinfo_claims(request_rec *r, oidc_session_t *z, json_t *userinfo_claims); 73 | json_t *oidc_session_get_userinfo_claims(request_rec *r, oidc_session_t *z); 74 | void oidc_session_set_idtoken_claims(request_rec *r, oidc_session_t *z, json_t *idtoken_claims); 75 | json_t *oidc_session_get_idtoken_claims(request_rec *r, oidc_session_t *z); 76 | void oidc_session_set_idtoken(request_rec *r, oidc_session_t *z, const char *s_id_token); 77 | const char *oidc_session_get_idtoken(request_rec *r, oidc_session_t *z); 78 | void oidc_session_set_access_token(request_rec *r, oidc_session_t *z, const char *access_token); 79 | const char *oidc_session_get_access_token(request_rec *r, oidc_session_t *z); 80 | void oidc_session_set_access_token_type(request_rec *r, oidc_session_t *z, const char *token_type); 81 | const char *oidc_session_get_access_token_type(request_rec *r, oidc_session_t *z); 82 | void oidc_session_set_access_token_expires(request_rec *r, oidc_session_t *z, const int expires_in); 83 | apr_time_t oidc_session_get_access_token_expires(request_rec *r, oidc_session_t *z); 84 | const char *oidc_session_get_access_token_expires2str(request_rec *r, oidc_session_t *z); 85 | void oidc_session_set_refresh_token(request_rec *r, oidc_session_t *z, const char *refresh_token); 86 | const char *oidc_session_get_refresh_token(request_rec *r, oidc_session_t *z); 87 | void oidc_session_set_session_expires(request_rec *r, oidc_session_t *z, const apr_time_t expires); 88 | apr_time_t oidc_session_get_session_expires(request_rec *r, oidc_session_t *z); 89 | void oidc_session_set_cookie_domain(request_rec *r, oidc_session_t *z, const char *cookie_domain); 90 | const char *oidc_session_get_cookie_domain(request_rec *r, oidc_session_t *z); 91 | void oidc_session_reset_userinfo_last_refresh(request_rec *r, oidc_session_t *z); 92 | void oidc_session_set_userinfo_refresh_interval(request_rec *r, oidc_session_t *z, const int interval); 93 | int oidc_session_get_userinfo_refresh_interval(request_rec *r, oidc_session_t *z); 94 | apr_time_t oidc_session_get_userinfo_last_refresh(request_rec *r, oidc_session_t *z); 95 | void oidc_session_set_access_token_last_refresh(request_rec *r, oidc_session_t *z, apr_time_t ts); 96 | apr_time_t oidc_session_get_access_token_last_refresh(request_rec *r, oidc_session_t *z); 97 | void oidc_session_set_request_state(request_rec *r, oidc_session_t *z, const char *request_state); 98 | const char *oidc_session_get_request_state(request_rec *r, oidc_session_t *z); 99 | void oidc_session_set_original_url(request_rec *r, oidc_session_t *z, const char *original_url); 100 | const char *oidc_session_get_original_url(request_rec *r, oidc_session_t *z); 101 | void oidc_session_set_session_state(request_rec *r, oidc_session_t *z, const char *session_state); 102 | const char *oidc_session_get_session_state(request_rec *r, oidc_session_t *z); 103 | void oidc_session_set_issuer(request_rec *r, oidc_session_t *z, const char *issuer); 104 | const char *oidc_session_get_issuer(request_rec *r, oidc_session_t *z); 105 | void oidc_session_set_client_id(request_rec *r, oidc_session_t *z, const char *client_id); 106 | void oidc_session_set_session_new(request_rec *r, oidc_session_t *z, const int is_new); 107 | int oidc_session_get_session_new(request_rec *r, oidc_session_t *z); 108 | const char *oidc_session_get_scope(request_rec *r, oidc_session_t *z); 109 | void oidc_session_set_scope(request_rec *r, oidc_session_t *z, const char *scope); 110 | 111 | #endif /* _MOD_AUTH_OPENIDC_SESSION_H_ */ 112 | -------------------------------------------------------------------------------- /src/handle/handle.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_HANDLE_H_ 44 | #define _MOD_AUTH_OPENIDC_HANDLE_H_ 45 | 46 | #include "cfg/dir.h" 47 | #include "const.h" // for the PACKAGE_* defines 48 | #include "jose.h" 49 | #include "session.h" 50 | #include 51 | #include 52 | #include 53 | 54 | // authz.c 55 | /* the name of the keyword that follows the Require primitive to indicate claims-based authorization */ 56 | #define OIDC_REQUIRE_CLAIM_NAME "claim" 57 | #ifdef USE_LIBJQ 58 | /* the name of the keyword that follows the Require primitive to indicate claims-expression-based authorization */ 59 | #define OIDC_REQUIRE_CLAIMS_EXPR_NAME "claims_expr" 60 | #endif 61 | typedef apr_byte_t (*oidc_authz_match_claim_fn_type)(request_rec *, const char *const, json_t *); 62 | apr_byte_t oidc_authz_match_claim(request_rec *r, const char *const attr_spec, json_t *claims); 63 | #ifdef USE_LIBJQ 64 | authz_status oidc_authz_24_checker_claims_expr(request_rec *r, const char *require_args, 65 | const void *parsed_require_args); 66 | #endif 67 | authz_status oidc_authz_24_checker_claim(request_rec *r, const char *require_args, const void *parsed_require_args); 68 | authz_status oidc_authz_24_worker(request_rec *r, json_t *claims, const char *require_args, 69 | const void *parsed_require_args, oidc_authz_match_claim_fn_type match_claim_fn); 70 | 71 | // content.c 72 | int oidc_content_handler(request_rec *r); 73 | 74 | // discovery.c 75 | int oidc_discovery_request(request_rec *r, oidc_cfg_t *cfg); 76 | apr_byte_t oidc_is_discovery_response(request_rec *r, oidc_cfg_t *cfg); 77 | int oidc_discovery_response(request_rec *r, oidc_cfg_t *c); 78 | 79 | // dpop.c 80 | int oidc_dpop_request(request_rec *r, oidc_cfg_t *c); 81 | 82 | // info.c 83 | int oidc_info_request(request_rec *r, oidc_cfg_t *c, oidc_session_t *session, apr_byte_t needs_save); 84 | 85 | // jwks_c. 86 | int oidc_jwks_request(request_rec *r, oidc_cfg_t *c); 87 | 88 | // logout.c 89 | int oidc_logout(request_rec *r, oidc_cfg_t *c, oidc_session_t *session); 90 | int oidc_logout_request(request_rec *r, oidc_cfg_t *c, oidc_session_t *session, const char *url, 91 | apr_byte_t revoke_tokens); 92 | 93 | // refresh.c 94 | apr_byte_t oidc_refresh_token_grant(request_rec *r, oidc_cfg_t *c, oidc_session_t *session, oidc_provider_t *provider, 95 | char **new_access_token, char **new_access_token_type, char **new_id_token); 96 | int oidc_refresh_token_request(request_rec *r, oidc_cfg_t *c, oidc_session_t *session); 97 | apr_byte_t oidc_refresh_access_token_before_expiry(request_rec *r, oidc_cfg_t *cfg, oidc_session_t *session, 98 | int ttl_minimum, apr_byte_t *needs_save); 99 | 100 | // request_uri.c 101 | int oidc_request_uri(request_rec *r, oidc_cfg_t *c); 102 | 103 | // request.c 104 | int oidc_request_authenticate_user(request_rec *r, oidc_cfg_t *c, oidc_provider_t *provider, const char *original_url, 105 | const char *login_hint, const char *id_token_hint, const char *prompt, 106 | const char *auth_request_params, const char *path_scope); 107 | apr_byte_t oidc_request_check_cookie_domain(request_rec *r, oidc_cfg_t *c, const char *original_url); 108 | 109 | // response.c 110 | apr_byte_t oidc_response_post_preserve_javascript(request_rec *r, const char *location, char **javascript, 111 | char **javascript_method); 112 | char *oidc_response_make_sid_iss_unique(request_rec *r, const char *sid, const char *issuer); 113 | int oidc_response_authorization_redirect(request_rec *r, oidc_cfg_t *c, oidc_session_t *session); 114 | int oidc_response_authorization_post(request_rec *r, oidc_cfg_t *c, oidc_session_t *session); 115 | apr_byte_t oidc_response_save_in_session(request_rec *r, oidc_cfg_t *c, oidc_session_t *session, 116 | oidc_provider_t *provider, const char *remoteUser, const char *id_token, 117 | oidc_jwt_t *id_token_jwt, const char *s_userinfo_claims, 118 | json_t *userinfo_claims, const char *access_token, 119 | const char *access_token_type, const int expires_in, const char *refresh_token, 120 | const char *scope, const char *session_state, const char *state, 121 | const char *original_url, const char *userinfo_jwt); 122 | 123 | // revoke.c 124 | int oidc_revoke_session(request_rec *r, oidc_cfg_t *c); 125 | int oidc_revoke_at_cache_remove(request_rec *r, oidc_cfg_t *c); 126 | 127 | // session_management.c 128 | int oidc_session_management(request_rec *r, oidc_cfg_t *c, oidc_session_t *session); 129 | 130 | // userinfo.c 131 | void oidc_userinfo_store_claims(request_rec *r, oidc_cfg_t *c, oidc_session_t *session, oidc_provider_t *provider, 132 | json_t *userinfo_claims, const char *userinfo_jwt); 133 | const char *oidc_userinfo_retrieve_claims(request_rec *r, oidc_cfg_t *c, oidc_provider_t *provider, 134 | const char *access_token, const char *access_token_type, 135 | oidc_session_t *session, char *id_token_sub, json_t **userinfo_claims, 136 | char **userinfo_jwt); 137 | apr_byte_t oidc_userinfo_refresh_claims(request_rec *r, oidc_cfg_t *cfg, oidc_session_t *session, 138 | apr_byte_t *needs_save); 139 | void oidc_userinfo_pass_as(request_rec *r, oidc_cfg_t *cfg, oidc_session_t *session, oidc_appinfo_pass_in_t pass_in, 140 | oidc_appinfo_encoding_t encoding); 141 | 142 | #endif // _MOD_AUTH_OPENIDC_HANDLE_H_ 143 | -------------------------------------------------------------------------------- /src/cfg/oauth.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_CFG_OAUTH_H_ 44 | #define _MOD_AUTH_OPENIDC_CFG_OAUTH_H_ 45 | 46 | #include "cfg/cfg.h" 47 | 48 | #define OIDCOAuthServerMetadataURL "OIDCOAuthServerMetadataURL" 49 | #define OIDCOAuthClientID "OIDCOAuthClientID" 50 | #define OIDCOAuthClientSecret "OIDCOAuthClientSecret" 51 | #define OIDCOAuthIntrospectionClientAuthBearerToken "OIDCOAuthIntrospectionClientAuthBearerToken" 52 | #define OIDCOAuthIntrospectionEndpoint "OIDCOAuthIntrospectionEndpoint" 53 | #define OIDCOAuthIntrospectionEndpointMethod "OIDCOAuthIntrospectionEndpointMethod" 54 | #define OIDCOAuthIntrospectionEndpointParams "OIDCOAuthIntrospectionEndpointParams" 55 | #define OIDCOAuthIntrospectionEndpointAuth "OIDCOAuthIntrospectionEndpointAuth" 56 | #define OIDCOAuthIntrospectionEndpointCert "OIDCOAuthIntrospectionEndpointCert" 57 | #define OIDCOAuthIntrospectionEndpointKey "OIDCOAuthIntrospectionEndpointKey" 58 | #define OIDCOAuthIntrospectionEndpointKeyPassword "OIDCOAuthIntrospectionEndpointKeyPassword" 59 | #define OIDCOAuthIntrospectionTokenParamName "OIDCOAuthIntrospectionTokenParamName" 60 | #define OIDCOAuthTokenExpiryClaim "OIDCOAuthTokenExpiryClaim" 61 | #define OIDCOAuthSSLValidateServer "OIDCOAuthSSLValidateServer" 62 | #define OIDCOAuthVerifyCertFiles "OIDCOAuthVerifyCertFiles" 63 | #define OIDCOAuthVerifySharedKeys "OIDCOAuthVerifySharedKeys" 64 | #define OIDCOAuthVerifyJwksUri "OIDCOAuthVerifyJwksUri" 65 | 66 | typedef enum { 67 | OIDC_TOKEN_EXPIRY_CLAIM_FORMAT_RELATIVE = 1, 68 | OIDC_TOKEN_EXPIRY_CLAIM_FORMAT_ABSOLUTE = 2 69 | } oidc_oauth_introspection_token_expiry_claim_format_t; 70 | 71 | typedef enum { 72 | OIDC_TOKEN_EXPIRY_CLAIM_REQUIRED_MANDATORY = 1, 73 | OIDC_TOKEN_EXPIRY_CLAIM_REQUIRED_OPTIONAL = 2 74 | } oidc_oauth_introspection_token_expiry_claim_required_t; 75 | 76 | typedef enum { 77 | OIDC_INTROSPECTION_METHOD_GET = 1, 78 | OIDC_INTROSPECTION_METHOD_POST = 2 79 | } oidc_oauth_introspection_endpoint_method_t; 80 | 81 | #define OIDC_CFG_OAUTH_MEMBER_FUNC_GET_DECL(member, type) \ 82 | type OIDC_CFG_MEMBER_FUNC_NAME(member, cfg_oauth, get)(oidc_cfg_t * cfg); 83 | 84 | #define OIDC_CMD_OAUTH_MEMBER_FUNC_DECL(member, ...) \ 85 | const char *OIDC_CFG_MEMBER_FUNC_NAME(member, cmd_oauth, set)(cmd_parms *, void *, ##__VA_ARGS__); 86 | 87 | #define OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(member, type, ...) \ 88 | OIDC_CMD_OAUTH_MEMBER_FUNC_DECL(member, const char *, ##__VA_ARGS__); \ 89 | OIDC_CFG_OAUTH_MEMBER_FUNC_GET_DECL(member, type) 90 | 91 | #define OIDC_CFG_OAUTH_MEMBER_FUNC_SET_DECL(member) \ 92 | const char *OIDC_CFG_MEMBER_FUNC_NAME(member, cfg_oauth, set)(apr_pool_t *, oidc_cfg_t *, const char *); 93 | 94 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(ssl_validate_server, int) 95 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(metadata_url, const char *) 96 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_url, const char *) 97 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_params, const char *) 98 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_auth, const char *) 99 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_auth_alg, const char *) 100 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_method, oidc_oauth_introspection_endpoint_method_t) 101 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_token_param_name, const char *) 102 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_tls_client_cert, const char *) 103 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_tls_client_key, const char *) 104 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_endpoint_tls_client_key_pwd, const char *) 105 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(client_id, const char *) 106 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(client_secret, const char *) 107 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(verify_jwks_uri, const char *) 108 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(verify_shared_keys, apr_hash_t *) 109 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(verify_public_keys, const apr_array_header_t *) 110 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(introspection_client_auth_bearer_token, const char *) 111 | 112 | // remote user claim, 3 args, 1 getter 113 | OIDC_CFG_OAUTH_MEMBER_FUNCS_DECL(remote_user_claim, oidc_remote_user_claim_t *, const char *, const char *) 114 | OIDC_CFG_OAUTH_MEMBER_FUNC_GET_DECL(remote_user_claim_name, const char *) 115 | 116 | // token expiry claim, 3 args, 3 getters 117 | OIDC_CMD_OAUTH_MEMBER_FUNC_DECL(token_expiry_claim, const char *, const char *, const char *) 118 | OIDC_CFG_OAUTH_MEMBER_FUNC_GET_DECL(introspection_token_expiry_claim_name, const char *) 119 | OIDC_CFG_OAUTH_MEMBER_FUNC_GET_DECL(introspection_token_expiry_claim_format, 120 | oidc_oauth_introspection_token_expiry_claim_format_t) 121 | OIDC_CFG_OAUTH_MEMBER_FUNC_GET_DECL(introspection_token_expiry_claim_required, 122 | oidc_oauth_introspection_token_expiry_claim_required_t) 123 | 124 | // needed in metadata.c 125 | OIDC_CFG_OAUTH_MEMBER_FUNC_SET_DECL(introspection_endpoint_url) 126 | OIDC_CFG_OAUTH_MEMBER_FUNC_SET_DECL(verify_jwks_uri) 127 | OIDC_CFG_OAUTH_MEMBER_FUNC_SET_DECL(introspection_endpoint_auth) 128 | OIDC_CFG_OAUTH_MEMBER_FUNC_GET_DECL(introspection_endpoint_auth_alg, const char *) 129 | 130 | typedef struct oidc_oauth_t oidc_oauth_t; 131 | 132 | oidc_oauth_t *oidc_cfg_oauth_create(apr_pool_t *pool); 133 | void oidc_cfg_oauth_merge(apr_pool_t *pool, oidc_oauth_t *dst, const oidc_oauth_t *base, const oidc_oauth_t *add); 134 | void oidc_cfg_oauth_destroy(oidc_oauth_t *o); 135 | 136 | #endif // _MOD_AUTH_OPENIDC_CFG_OAUTH_H_ 137 | -------------------------------------------------------------------------------- /src/proto/jwks.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #include "metadata.h" 44 | #include "proto/proto.h" 45 | #include "util/util.h" 46 | 47 | /* 48 | * get the key from the JWKs that corresponds with the key specified in the header 49 | */ 50 | static apr_byte_t oidc_proto_jwks_key_get(request_rec *r, oidc_jwt_t *jwt, json_t *j_jwks, apr_hash_t *result) { 51 | 52 | apr_byte_t rc = TRUE; 53 | oidc_jwk_t *jwk = NULL; 54 | oidc_jose_error_t err; 55 | char *jwk_json = NULL; 56 | 57 | /* get the (optional) thumbprint for comparison */ 58 | const char *x5t = oidc_jwt_hdr_get(jwt, OIDC_JOSE_JWK_X5T_STR); 59 | oidc_debug(r, "search for kid \"%s\" or thumbprint x5t \"%s\"", jwt->header.kid, x5t); 60 | 61 | /* get the "keys" JSON array from the JWKs object */ 62 | json_t *keys = json_object_get(j_jwks, OIDC_JOSE_JWKS_KEYS_STR); 63 | if ((keys == NULL) || !(json_is_array(keys))) { 64 | oidc_error(r, "\"%s\" array element is not a JSON array", OIDC_JOSE_JWKS_KEYS_STR); 65 | return FALSE; 66 | } 67 | 68 | int i; 69 | for (i = 0; i < json_array_size(keys); i++) { 70 | 71 | /* get the next element in the array */ 72 | json_t *elem = json_array_get(keys, i); 73 | 74 | if (oidc_jwk_parse_json(r->pool, elem, &jwk, &err) == FALSE) { 75 | oidc_warn(r, "oidc_jwk_parse_json failed: %s", oidc_jose_e2s(r->pool, err)); 76 | continue; 77 | } 78 | 79 | /* get the key type and see if it is the type that we are looking for */ 80 | if (oidc_jwt_alg2kty(jwt) != jwk->kty) { 81 | oidc_debug( 82 | r, 83 | "skipping non matching kty=%d for kid=%s because it doesn't match requested kty=%d, kid=%s", 84 | jwk->kty, jwk->kid, oidc_jwt_alg2kty(jwt), jwt->header.kid); 85 | oidc_jwk_destroy(jwk); 86 | continue; 87 | } 88 | 89 | /* see if we were looking for a specific kid, if not we'll include any key that matches the type */ 90 | if ((jwt->header.kid == NULL) && (x5t == NULL)) { 91 | const char *use = json_string_value(json_object_get(elem, OIDC_JOSE_JWK_USE_STR)); 92 | if ((use != NULL) && (_oidc_strcmp(use, OIDC_JOSE_JWK_SIG_STR) != 0)) { 93 | oidc_debug(r, "skipping key because of non-matching \"%s\": \"%s\"", 94 | OIDC_JOSE_JWK_USE_STR, use); 95 | oidc_jwk_destroy(jwk); 96 | } else { 97 | oidc_jwk_to_json(r->pool, jwk, &jwk_json, &err); 98 | oidc_debug(r, "no kid/x5t to match, include matching key type: %s", jwk_json); 99 | if (jwk->kid != NULL) 100 | apr_hash_set(result, jwk->kid, APR_HASH_KEY_STRING, jwk); 101 | else 102 | // can do this because we never remove anything from the list 103 | apr_hash_set(result, apr_psprintf(r->pool, "%d", apr_hash_count(result)), 104 | APR_HASH_KEY_STRING, jwk); 105 | } 106 | continue; 107 | } 108 | 109 | /* we are looking for a specific kid, get the kid from the current element */ 110 | /* compare the requested kid against the current element */ 111 | if ((jwt->header.kid != NULL) && (jwk->kid != NULL) && (_oidc_strcmp(jwt->header.kid, jwk->kid) == 0)) { 112 | oidc_jwk_to_json(r->pool, jwk, &jwk_json, &err); 113 | oidc_debug(r, "found matching kid: \"%s\" for jwk: %s", jwt->header.kid, jwk_json); 114 | apr_hash_set(result, jwt->header.kid, APR_HASH_KEY_STRING, jwk); 115 | break; 116 | } 117 | 118 | /* we are looking for a specific x5t, get the x5t from the current element */ 119 | char *s_x5t = NULL; 120 | oidc_util_json_object_get_string(r->pool, elem, OIDC_JOSE_JWK_X5T_STR, &s_x5t, NULL); 121 | /* compare the requested thumbprint against the current element */ 122 | if ((s_x5t != NULL) && (x5t != NULL) && (_oidc_strcmp(x5t, s_x5t) == 0)) { 123 | oidc_jwk_to_json(r->pool, jwk, &jwk_json, &err); 124 | oidc_debug(r, "found matching %s: \"%s\" for jwk: %s", OIDC_JOSE_JWK_X5T_STR, x5t, jwk_json); 125 | apr_hash_set(result, x5t, APR_HASH_KEY_STRING, jwk); 126 | break; 127 | } 128 | 129 | /* the right key type but no matching kid/x5t */ 130 | oidc_jwk_destroy(jwk); 131 | } 132 | 133 | return rc; 134 | } 135 | 136 | /* 137 | * get the keys from the (possibly cached) set of JWKs on the jwk_uri that corresponds with the key specified in the 138 | * header 139 | */ 140 | apr_byte_t oidc_proto_jwks_uri_keys(request_rec *r, oidc_cfg_t *cfg, oidc_jwt_t *jwt, const oidc_jwks_uri_t *jwks_uri, 141 | int ssl_validate_server, apr_hash_t *keys, apr_byte_t *force_refresh) { 142 | 143 | json_t *j_jwks = NULL; 144 | 145 | /* get the set of JSON Web Keys for this provider (possibly by downloading them from the specified 146 | * provider->jwk_uri) */ 147 | oidc_metadata_jwks_get(r, cfg, jwks_uri, ssl_validate_server, &j_jwks, force_refresh); 148 | if (j_jwks == NULL) { 149 | oidc_error(r, "could not %s JSON Web Keys", *force_refresh ? "refresh" : "get"); 150 | return FALSE; 151 | } 152 | 153 | /* 154 | * get the key corresponding to the kid from the header, referencing the key that 155 | * was used to sign this message (or get all keys in case no kid was set) 156 | * 157 | * we don't check the error return value because we'll treat "error" in the same 158 | * way as "key not found" i.e. by refreshing the keys from the JWKs URI if not 159 | * already done 160 | */ 161 | oidc_proto_jwks_key_get(r, jwt, j_jwks, keys); 162 | 163 | /* no need anymore for the parsed json_t contents, release the it */ 164 | json_decref(j_jwks); 165 | 166 | /* if we've got no keys and we did not do a fresh download, then the cache may be stale */ 167 | if ((apr_hash_count(keys) < 1) && (*force_refresh == FALSE)) { 168 | 169 | /* we did not get a key, but we have not refreshed the JWKs from the jwks_uri yet */ 170 | oidc_warn(r, "could not find a key in the cached JSON Web Keys, doing a forced refresh in case keys " 171 | "were rolled over"); 172 | /* get the set of JSON Web Keys forcing a fresh download from the specified JWKs URI */ 173 | *force_refresh = TRUE; 174 | return oidc_proto_jwks_uri_keys(r, cfg, jwt, jwks_uri, ssl_validate_server, keys, force_refresh); 175 | } 176 | 177 | oidc_debug(r, "returning %d key(s) obtained from the (possibly cached) JWKs URI", apr_hash_count(keys)); 178 | 179 | return TRUE; 180 | } 181 | -------------------------------------------------------------------------------- /src/mod_auth_openidc.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * Copyright (C) 2013-2017 Ping Identity Corporation 23 | * All rights reserved. 24 | * 25 | * DISCLAIMER OF WARRANTIES: 26 | * 27 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 28 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 29 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 30 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 31 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 32 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 33 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 34 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 35 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 36 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 37 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 38 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 39 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 40 | * 41 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 42 | */ 43 | 44 | #ifndef _MOD_AUTH_OPENIDC_H_ 45 | #define _MOD_AUTH_OPENIDC_H_ 46 | 47 | #include "cfg/cfg.h" 48 | #include "cfg/provider.h" 49 | #include "session.h" 50 | 51 | #define OIDC_AUTH_TYPE_OPENID_CONNECT "openid-connect" 52 | #define OIDC_AUTH_TYPE_OPENID_OAUTH20 "oauth20" 53 | #define OIDC_AUTH_TYPE_OPENID_BOTH "auth-openidc" 54 | 55 | /* keys for storing info in the request state */ 56 | #define OIDC_REQUEST_STATE_KEY_AUTHN_POST "a" 57 | #define OIDC_REQUEST_STATE_KEY_CLAIMS "c" 58 | #define OIDC_REQUEST_STATE_KEY_DISCOVERY "d" 59 | #define OIDC_REQUEST_STATE_KEY_HTTP "hp" 60 | #define OIDC_REQUEST_STATE_KEY_HTML "hl" 61 | #define OIDC_REQUEST_STATE_KEY_IDTOKEN "i" 62 | #define OIDC_REQUEST_STATE_KEY_SCOPE "sc" 63 | #define OIDC_REQUEST_STATE_KEY_AUTHN_PRESERVE "p" 64 | #define OIDC_REQUEST_STATE_KEY_SAVE "s" 65 | #define OIDC_REQUEST_STATE_TRACE_ID "t" 66 | 67 | /* parameter name of the original method in the discovery response */ 68 | #define OIDC_DISC_RM_PARAM "method" 69 | 70 | /* default prefix for information passed in HTTP headers */ 71 | #define OIDC_DEFAULT_HEADER_PREFIX "OIDC_" 72 | 73 | /* the (global) key for the mod_auth_openidc related state that is stored in the request userdata context */ 74 | #define OIDC_USERDATA_KEY "mod_auth_openidc_state" 75 | #define OIDC_USERDATA_SESSION "mod_auth_openidc_session" 76 | #define OIDC_USERDATA_POST_PARAMS_KEY "oidc_userdata_post_params" 77 | 78 | #define OIDC_POST_PRESERVE_ESCAPE_NONE 0 79 | #define OIDC_POST_PRESERVE_ESCAPE_HTML 1 80 | #define OIDC_POST_PRESERVE_ESCAPE_JAVASCRIPT 2 81 | 82 | /* defines for how long provider metadata will be cached */ 83 | #define OIDC_CACHE_PROVIDER_METADATA_EXPIRY_DEFAULT 86400 84 | 85 | /* define the parameter value for the "logout" request that indicates a GET-style logout call from the OP */ 86 | #define OIDC_GET_STYLE_LOGOUT_PARAM_VALUE "get" 87 | #define OIDC_IMG_STYLE_LOGOUT_PARAM_VALUE "img" 88 | #define OIDC_BACKCHANNEL_STYLE_LOGOUT_PARAM_VALUE "backchannel" 89 | 90 | /* http methods */ 91 | #define OIDC_METHOD_GET "get" 92 | #define OIDC_METHOD_FORM_POST "form_post" 93 | 94 | #define OIDC_REDIRECT_URI_REQUEST_INFO "info" 95 | #define OIDC_REDIRECT_URI_REQUEST_DPOP "dpop" 96 | #define OIDC_REDIRECT_URI_REQUEST_LOGOUT "logout" 97 | #define OIDC_REDIRECT_URI_REQUEST_JWKS "jwks" 98 | #define OIDC_REDIRECT_URI_REQUEST_SESSION "session" 99 | #define OIDC_REDIRECT_URI_REQUEST_REFRESH "refresh" 100 | #define OIDC_REDIRECT_URI_REQUEST_REMOVE_AT_CACHE "remove_at_cache" 101 | #define OIDC_REDIRECT_URI_REQUEST_REVOKE_SESSION "revoke_session" 102 | #define OIDC_REDIRECT_URI_REQUEST_REQUEST_URI "request_uri" 103 | #define OIDC_REDIRECT_URI_REQUEST_SID "sid" 104 | #define OIDC_REDIRECT_URI_REQUEST_ISS "iss" 105 | 106 | #define OIDC_INFO_PARAM_EXTEND_SESSION "extend_session" 107 | 108 | #define OIDC_CLAIM_ISS "iss" 109 | #define OIDC_CLAIM_AUD "aud" 110 | #define OIDC_CLAIM_AZP "azp" 111 | #define OIDC_CLAIM_SUB "sub" 112 | #define OIDC_CLAIM_JTI "jti" 113 | #define OIDC_CLAIM_EXP "exp" 114 | #define OIDC_CLAIM_IAT "iat" 115 | #define OIDC_CLAIM_NBF "nbf" 116 | #define OIDC_CLAIM_NONCE "nonce" 117 | #define OIDC_CLAIM_AT_HASH "at_hash" 118 | #define OIDC_CLAIM_C_HASH "c_hash" 119 | #define OIDC_CLAIM_RFP "rfp" 120 | #define OIDC_CLAIM_TARGET_LINK_URI "target_link_uri" 121 | #define OIDC_CLAIM_SID "sid" 122 | #define OIDC_CLAIM_EVENTS "events" 123 | #define OIDC_CLAIM_TYP "typ" 124 | #define OIDC_CLAIM_JWK "jwk" 125 | #define OIDC_CLAIM_HTM "htm" 126 | #define OIDC_CLAIM_HTU "htu" 127 | #define OIDC_CLAIM_ATH "ath" 128 | #define OIDC_CLAIM_SCOPE "scope" 129 | 130 | #define OIDC_APP_INFO_REFRESH_TOKEN "refresh_token" 131 | #define OIDC_APP_INFO_SCOPE "scope" 132 | #define OIDC_APP_INFO_ACCESS_TOKEN "access_token" 133 | #define OIDC_APP_INFO_ACCESS_TOKEN_TYPE "access_token_type" 134 | #define OIDC_APP_INFO_ACCESS_TOKEN_EXP "access_token_expires" 135 | #define OIDC_APP_INFO_ID_TOKEN "id_token" 136 | #define OIDC_APP_INFO_ID_TOKEN_PAYLOAD "id_token_payload" 137 | #define OIDC_APP_INFO_USERINFO_JSON "userinfo_json" 138 | #define OIDC_APP_INFO_USERINFO_JWT "userinfo_jwt" 139 | #define OIDC_APP_INFO_SIGNED_JWT "signed_jwt" 140 | 141 | int oidc_check_user_id(request_rec *r); 142 | int oidc_fixups(request_rec *r); 143 | apr_byte_t oidc_enabled(request_rec *r, oidc_cfg_t *c); 144 | 145 | void oidc_request_state_set(request_rec *r, const char *key, const char *value); 146 | const char *oidc_request_state_get(request_rec *r, const char *key); 147 | json_t *oidc_request_state_json_get(request_rec *r, const char *key); 148 | void oidc_request_state_json_set(request_rec *r, const char *key, json_t *value); 149 | 150 | void oidc_scrub_headers(request_rec *r); 151 | void oidc_strip_cookies(request_rec *r); 152 | apr_byte_t oidc_get_remote_user(request_rec *r, const char *claim_name, const char *replace, const char *reg_exp, 153 | json_t *json, char **request_user); 154 | apr_byte_t oidc_get_provider_from_session(request_rec *r, oidc_cfg_t *c, oidc_session_t *session, 155 | oidc_provider_t **provider); 156 | apr_byte_t oidc_check_cookie_domain(request_rec *r, oidc_cfg_t *cfg, oidc_session_t *session); 157 | apr_byte_t oidc_session_pass_tokens(request_rec *r, oidc_cfg_t *cfg, oidc_session_t *session, apr_byte_t extend_session, 158 | apr_byte_t *needs_save); 159 | void oidc_log_session_expires(request_rec *r, const char *msg, apr_time_t session_expires); 160 | apr_byte_t oidc_provider_static_config(request_rec *r, oidc_cfg_t *c, oidc_provider_t **provider); 161 | const char *oidc_original_request_method(request_rec *r, oidc_cfg_t *cfg, apr_byte_t handle_discovery_response); 162 | oidc_provider_t *oidc_get_provider_for_issuer(request_rec *r, oidc_cfg_t *c, const char *issuer, 163 | apr_byte_t allow_discovery); 164 | int oidc_clean_expired_state_cookies(request_rec *r, oidc_cfg_t *c, const char *currentCookieName, int delete_oldest); 165 | apr_byte_t oidc_is_auth_capable_request(request_rec *r); 166 | apr_byte_t oidc_validate_redirect_url(request_rec *r, oidc_cfg_t *c, const char *redirect_to_url, 167 | apr_byte_t restrict_to_host, char **err_str, char **err_desc); 168 | apr_byte_t oidc_set_app_claims(request_rec *r, oidc_cfg_t *cfg, json_t *claims); 169 | 170 | #endif /* _MOD_AUTH_OPENIDC_H_ */ 171 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://github.com/OpenIDC/mod_auth_openidc/actions/workflows/build.yml/badge.svg)](https://github.com/OpenIDC/mod_auth_openidc/actions/workflows/build.yml) 2 | [OpenID Certification](https://openid.net/certification) 3 | [![CodeQL Analysis](https://github.com/OpenIDC/mod_auth_openidc/actions/workflows/codeql-analysis.yml/badge.svg)](https://github.com/OpenIDC/mod_auth_openidc/actions/workflows/codeql-analysis.yml) 4 | [![Coverity Scan Build Status](https://scan.coverity.com/projects/31119/badge.svg)](https://scan.coverity.com/projects/openidc-mod_auth_openidc) 5 | 6 | mod_auth_openidc 7 | ================ 8 | 9 | *mod_auth_openidc* is an OpenID Certified™ authentication and authorization module for the Apache 2.x 10 | HTTP server that implements the OpenID Connect 1.x and FAPI 2.x Relying Party functionality. 11 | 12 | Overview 13 | -------- 14 | 15 | This module enables an Apache 2.x web server to operate as an [OpenID Connect](http://openid.net/specs/openid-connect-core-1_0.html) 16 | *Relying Party* (RP) towards an OpenID Connect *Provider* (OP). It relays end user authentication to a Provider and 17 | receives user identity information from that Provider. It then passes on that identity information (a.k.a. claims) 18 | to applications protected by the Apache web server and establishes an authentication session for the identified user. 19 | 20 | The protected content, applications and services can be hosted by the Apache server itself or served from 21 | origin server(s) residing behind it by configuring Apache as a Reverse Proxy in front of those servers. The 22 | latter allows for adding OpenID Connect based authentication to existing applications/services/SPAs without 23 | modifying those applications, possibly migrating them away from legacy authentication mechanisms to standards-based 24 | OpenID Connect Single Sign On (SSO). 25 | 26 | By default the module sets the `REMOTE_USER` variable to the `id_token` `[sub]` claim, concatenated with the OP's Issuer 27 | identifier (`[sub]@[iss]`). Other `id_token` claims are passed in HTTP headers and/or environment variables together with those 28 | (optionally) obtained from the UserInfo endpoint. The provided HTTP headers and environment variables can be consumed by 29 | applications protected by the Apache server. 30 | 31 | Custom fine-grained authorization rules - based on Apache's `Require` primitives - can be specified to match against the 32 | set of claims provided in the `id_token`/ `userinfo` claims, see [here](https://github.com/OpenIDC/mod_auth_openidc/wiki/Authorization). 33 | Clustering for resilience and performance can be configured using one of the supported cache backends options as 34 | listed [here](https://github.com/OpenIDC/mod_auth_openidc/wiki/Caching). 35 | 36 | For a complete overview of all configuration options, see the file [`auth_openidc.conf`](https://github.com/OpenIDC/mod_auth_openidc/blob/master/auth_openidc.conf). 37 | This file can also serve as an include file for `httpd.conf`. 38 | 39 | How to Use It 40 | ------------- 41 | 42 | 1. install and load `mod_auth_openidc.so` in your Apache server 43 | 1. set `OIDCRedirectURI` to a "vanity" URL within a location that is protected by mod_auth_openidc 44 | 45 | 1. configure `OIDCProviderMetadataURL` so it points to the Discovery metadata of your OpenID Connect Provider served on the `.well-known/openid-configuration` endpoint 46 | 1. register/generate a Client identifier and a secret with the OpenID Connect Provider and configure those in `OIDCClientID` and `OIDCClientSecret` respectively 47 | 1. register the `OIDCRedirectURI` configured above as the Redirect or Callback URI for your client at the Provider 48 | 1. configure your protected content/locations with `AuthType openid-connect` 49 | 50 | A minimal working configuration would look like: 51 | ```apache 52 | LoadModule auth_openidc_module modules/mod_auth_openidc.so 53 | 54 | # OIDCRedirectURI is a vanity URL that must point to a path protected by this module but must NOT point to any content 55 | OIDCRedirectURI https:///secure/redirect_uri 56 | 57 | OIDCProviderMetadataURL /.well-known/openid-configuration 58 | OIDCClientID 59 | OIDCClientSecret 60 | 61 | 62 | AuthType openid-connect 63 | Require valid-user 64 | 65 | ``` 66 | For claims-based authorization with `Require claim:` directives see the [Wiki page on Authorization](https://github.com/OpenIDC/mod_auth_openidc/wiki/Authorization). For details on configuring multiple providers see the [Wiki](https://github.com/OpenIDC/mod_auth_openidc/wiki/Multiple-Providers). 67 | 68 | ### Quickstart for specific Providers 69 | 70 | - [Keycloak](https://github.com/OpenIDC/mod_auth_openidc/wiki/Keycloak) 71 | - [Microsoft Entra ID (Azure AD)](https://github.com/OpenIDC/mod_auth_openidc/wiki/Microsoft-Entra-ID--(Azure-AD)) 72 | - [Google Accounts](https://github.com/OpenIDC/mod_auth_openidc/wiki/Google-Accounts) 73 | - [Sign in with Apple](https://github.com/OpenIDC/mod_auth_openidc/wiki/Sign-in-with-Apple) 74 | - [GLUU Server](https://github.com/OpenIDC/mod_auth_openidc/wiki/Gluu-Server) 75 | - [Curity Identity Server](https://github.com/OpenIDC/mod_auth_openidc/wiki/Curity-Identity-Server) 76 | and [more](https://github.com/OpenIDC/mod_auth_openidc/wiki/Useful-Links) 77 | 78 | See the [Wiki](https://github.com/OpenIDC/mod_auth_openidc/wiki) for configuration docs for other OpenID Connect Providers. 79 | 80 | Interoperability and Supported Specifications 81 | --------------------------------------------- 82 | 83 | *mod_auth_openidc* is [OpenID Certified™](https://openid.net/certification/#OPENID-RP-P) and supports the following specifications: 84 | - [OpenID Connect Core 1.0](http://openid.net/specs/openid-connect-core-1_0.html) *(Basic, Implicit, Hybrid and Refresh flows)* 85 | - [RFC 7636 - Proof Key for Code Exchange by OAuth Public Clients](https://datatracker.ietf.org/doc/html/rfc7636) 86 | - [FAPI 2.0 Security Profile](https://openid.net/specs/fapi-security-profile-2_0-final.html) 87 | - [FAPI 2.0 Message Signing](https://openid.net/specs/fapi-message-signing-2_0.html) 88 | - [RFC 9126 - OAuth 2.0 Pushed Authorization Requests](https://datatracker.ietf.org/doc/html/rfc9126) 89 | - [RFC 9449 - OAuth 2.0 Demonstrating Proof of Possession (DPoP)](https://tools.ietf.org/html/rfc9449) 90 | - [OpenID Connect Discovery 1.0](http://openid.net/specs/openid-connect-discovery-1_0.html) 91 | - [OpenID Connect Dynamic Client Registration 1.0](http://openid.net/specs/openid-connect-registration-1_0.html) 92 | - [OAuth 2.0 Form Post Response Mode 1.0](http://openid.net/specs/oauth-v2-form-post-response-mode-1_0.html) 93 | - [OAuth 2.0 Multiple Response Type Encoding Practices 1.0](http://openid.net/specs/oauth-v2-multiple-response-types-1_0.html) 94 | - [OpenID Connect Session Management 1.0](http://openid.net/specs/openid-connect-session-1_0.html) *see the [Wiki](https://github.com/OpenIDC/mod_auth_openidc/wiki/OpenID-Connect-Session-Management) for information on how to configure it)* 95 | - [OpenID Connect Front-Channel Logout 1.0](http://openid.net/specs/openid-connect-frontchannel-1_0.html) 96 | - [OpenID Connect Back-Channel Logout 1.0](https://openid.net/specs/openid-connect-backchannel-1_0.html) 97 | 98 | Support 99 | ------- 100 | 101 | #### Community 102 | Documentation can be found at the Wiki (including Frequently Asked Questions) at: 103 | [https://github.com/OpenIDC/mod_auth_openidc/wiki](https://github.com/OpenIDC/mod_auth_openidc/wiki) 104 | For questions, issues and suggestions use the Github Discussions forum at: 105 | [https://github.com/OpenIDC/mod_auth_openidc/discussions](https://github.com/OpenIDC/mod_auth_openidc/discussions) 106 | 107 | #### Commercial 108 | Licensed builds with support for Redis/Valkey over TLS, Redis Sentinel/Cluster as well as binary packages for Microsoft Windows, EOL Red Hat, Ubuntu and Debian releases, Oracle HTTP Server and IBM HTTP Server are available under a commercial agreement. 109 | 110 | For inquiries about commercial - subscription based - support and licensing please contact: 111 | [sales@openidc.com](mailto:sales@openidc.com) 112 | 113 | Disclaimer 114 | ---------- 115 | 116 | *This software is open sourced by OpenIDC, a subsidiary of ZmartZone Holding B.V. For commercial services 117 | you can contact [OpenIDC](https://www.openidc.com) as described above in the [Support](#support) section.* 118 | -------------------------------------------------------------------------------- /src/cfg/dir.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Licensed to the Apache Software Foundation (ASF) under one 3 | * or more contributor license agreements. See the NOTICE file 4 | * distributed with this work for additional information 5 | * regarding copyright ownership. The ASF licenses this file 6 | * to you under the Apache License, Version 2.0 (the 7 | * "License"); you may not use this file except in compliance 8 | * with the License. You may obtain a copy of the License at 9 | * 10 | * http://www.apache.org/licenses/LICENSE-2.0 11 | * 12 | * Unless required by applicable law or agreed to in writing, 13 | * software distributed under the License is distributed on an 14 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | * KIND, either express or implied. See the License for the 16 | * specific language governing permissions and limitations 17 | * under the License. 18 | */ 19 | 20 | /*************************************************************************** 21 | * Copyright (C) 2017-2025 ZmartZone Holding BV 22 | * All rights reserved. 23 | * 24 | * DISCLAIMER OF WARRANTIES: 25 | * 26 | * THE SOFTWARE PROVIDED HEREUNDER IS PROVIDED ON AN "AS IS" BASIS, WITHOUT 27 | * ANY WARRANTIES OR REPRESENTATIONS EXPRESS, IMPLIED OR STATUTORY; INCLUDING, 28 | * WITHOUT LIMITATION, WARRANTIES OF QUALITY, PERFORMANCE, NONINFRINGEMENT, 29 | * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. NOR ARE THERE ANY 30 | * WARRANTIES CREATED BY A COURSE OR DEALING, COURSE OF PERFORMANCE OR TRADE 31 | * USAGE. FURTHERMORE, THERE ARE NO WARRANTIES THAT THE SOFTWARE WILL MEET 32 | * YOUR NEEDS OR BE FREE FROM ERRORS, OR THAT THE OPERATION OF THE SOFTWARE 33 | * WILL BE UNINTERRUPTED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR 34 | * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 35 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES HOWEVER CAUSED AND ON ANY THEORY OF 36 | * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 37 | * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 38 | * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 39 | * 40 | * @Author: Hans Zandbelt - hans.zandbelt@openidc.com 41 | */ 42 | 43 | #ifndef _MOD_AUTH_OPENIDC_CFG_DIR_H_ 44 | #define _MOD_AUTH_OPENIDC_CFG_DIR_H_ 45 | 46 | #include "cfg/cfg.h" 47 | 48 | #define OIDCPathScope "OIDCPathScope" 49 | #define OIDCPathAuthRequestParams "OIDCPathAuthRequestParams" 50 | #define OIDCDiscoverURL "OIDCDiscoverURL" 51 | #define OIDCPassCookies "OIDCPassCookies" 52 | #define OIDCStripCookies "OIDCStripCookies" 53 | #define OIDCAuthNHeader "OIDCAuthNHeader" 54 | #define OIDCCookie "OIDCCookie" 55 | #define OIDCUnAuthAction "OIDCUnAuthAction" 56 | #define OIDCUnAutzAction "OIDCUnAutzAction" 57 | #define OIDCPassClaimsAs "OIDCPassClaimsAs" 58 | #define OIDCOAuthAcceptTokenAs "OIDCOAuthAcceptTokenAs" 59 | #define OIDCOAuthTokenIntrospectionInterval "OIDCOAuthTokenIntrospectionInterval" 60 | #define OIDCPreservePost "OIDCPreservePost" 61 | #define OIDCPassAccessToken "OIDCPassAccessToken" 62 | #define OIDCPassRefreshToken "OIDCPassRefreshToken" 63 | #define OIDCRefreshAccessTokenBeforeExpiry "OIDCRefreshAccessTokenBeforeExpiry" 64 | #define OIDCStateCookiePrefix "OIDCStateCookiePrefix" 65 | #define OIDCPassIDTokenAs "OIDCPassIDTokenAs" 66 | #define OIDCPassUserInfoAs "OIDCPassUserInfoAs" 67 | #define OIDCUserInfoClaimsExpr "OIDCUserInfoClaimsExpr" 68 | #define OIDCCookiePath "OIDCCookiePath" 69 | 70 | typedef enum { 71 | /* pass id_token as individual claims in headers (default) */ 72 | OIDC_PASS_IDTOKEN_AS_CLAIMS = 1, 73 | /* pass id_token payload as JSON object in header */ 74 | OIDC_PASS_IDTOKEN_AS_PAYLOAD = 2, 75 | /* pass id_token in compact serialized format in header */ 76 | OIDC_PASS_IDTOKEN_AS_SERIALIZED = 4, 77 | /* do not pass id_token */ 78 | OIDC_PASS_IDTOKEN_OFF = 8 79 | } oidc_pass_idtoken_as_t; 80 | 81 | typedef enum { 82 | /* accept bearer token in header (default) */ 83 | OIDC_OAUTH_ACCEPT_TOKEN_IN_HEADER = 1, 84 | /* accept bearer token as a post parameter */ 85 | OIDC_OAUTH_ACCEPT_TOKEN_IN_POST = 2, 86 | /* accept bearer token as a query parameter */ 87 | OIDC_OAUTH_ACCEPT_TOKEN_IN_QUERY = 4, 88 | /* accept bearer token as a cookie parameter (PingAccess) */ 89 | OIDC_OAUTH_ACCEPT_TOKEN_IN_COOKIE = 8, 90 | /* accept bearer token as basic auth password (non-oauth clients) */ 91 | OIDC_OAUTH_ACCEPT_TOKEN_IN_BASIC = 16 92 | } oidc_oauth_accept_token_in_t; 93 | 94 | typedef enum { 95 | OIDC_APPINFO_PASS_NONE = 0, 96 | OIDC_APPINFO_PASS_HEADERS = 1, 97 | OIDC_APPINFO_PASS_ENVVARS = 2, 98 | } oidc_appinfo_pass_in_t; 99 | 100 | typedef enum { 101 | OIDC_APPINFO_ENCODING_NONE = 0, 102 | OIDC_APPINFO_ENCODING_BASE64URL = 1, 103 | OIDC_APPINFO_ENCODING_LATIN1 = 2 104 | } oidc_appinfo_encoding_t; 105 | 106 | /* the hash key of the cookie name value in the list of options */ 107 | #define OIDC_OAUTH_ACCEPT_TOKEN_IN_OPTION_COOKIE_NAME "cookie-name" 108 | 109 | typedef enum { 110 | OIDC_UNAUTH_AUTHENTICATE = 1, 111 | OIDC_UNAUTH_PASS = 2, 112 | OIDC_UNAUTH_RETURN401 = 3, 113 | OIDC_UNAUTH_RETURN410 = 4, 114 | OIDC_UNAUTH_RETURN407 = 5 115 | } oidc_unauth_action_t; 116 | 117 | typedef enum { 118 | OIDC_UNAUTZ_RETURN403 = 1, 119 | OIDC_UNAUTZ_RETURN401 = 2, 120 | OIDC_UNAUTZ_AUTHENTICATE = 3, 121 | OIDC_UNAUTZ_RETURN302 = 4 122 | } oidc_unautz_action_t; 123 | 124 | #define OIDC_CMD_DIR_MEMBER_FUNC_DECL(member, ...) \ 125 | const char *OIDC_CFG_MEMBER_FUNC_NAME(member, cmd_dir, set)(cmd_parms *, void *, const char *, ##__VA_ARGS__); 126 | 127 | #define OIDC_CFG_DIR_MEMBER_FUNC_GET_DECL(member, type) \ 128 | type OIDC_CFG_MEMBER_FUNC_NAME(member, cfg_dir, get)(request_rec * r); 129 | 130 | #define OIDC_CFG_DIR_MEMBER_FUNCS(member, type, ...) \ 131 | OIDC_CMD_DIR_MEMBER_FUNC_DECL(member, ##__VA_ARGS__) \ 132 | OIDC_CFG_DIR_MEMBER_FUNC_GET_DECL(member, type) 133 | 134 | OIDC_CFG_DIR_MEMBER_FUNCS(pass_userinfo_as, const apr_array_header_t *) 135 | OIDC_CFG_DIR_MEMBER_FUNCS(accept_oauth_token_in, int) 136 | OIDC_CFG_DIR_MEMBER_FUNCS(preserve_post, int) 137 | OIDC_CFG_DIR_MEMBER_FUNCS(pass_claims_as, int, const char *) 138 | OIDC_CFG_DIR_MEMBER_FUNCS(unauth_action, oidc_unauth_action_t, const char *) 139 | OIDC_CFG_DIR_MEMBER_FUNCS(path_scope, const char *) 140 | OIDC_CFG_DIR_MEMBER_FUNCS(path_auth_request_params, const char *) 141 | OIDC_CFG_DIR_MEMBER_FUNCS(authn_header, const char *) 142 | OIDC_CFG_DIR_MEMBER_FUNCS(cookie_path, const char *) 143 | OIDC_CFG_DIR_MEMBER_FUNCS(cookie, const char *) 144 | OIDC_CFG_DIR_MEMBER_FUNCS(pass_cookies, const apr_array_header_t *) 145 | OIDC_CFG_DIR_MEMBER_FUNCS(strip_cookies, const apr_array_header_t *) 146 | OIDC_CFG_DIR_MEMBER_FUNCS(token_introspection_interval, int) 147 | OIDC_CFG_DIR_MEMBER_FUNCS(pass_access_token, apr_byte_t) 148 | OIDC_CFG_DIR_MEMBER_FUNCS(pass_refresh_token, apr_byte_t) 149 | OIDC_CFG_DIR_MEMBER_FUNCS(discover_url, const char *) 150 | OIDC_CFG_DIR_MEMBER_FUNCS(state_cookie_prefix, const char *) 151 | OIDC_CFG_DIR_MEMBER_FUNCS(pass_idtoken_as, oidc_pass_idtoken_as_t) 152 | 153 | // 2 args 154 | OIDC_CFG_DIR_MEMBER_FUNCS(unautz_action, oidc_unautz_action_t, const char *) 155 | OIDC_CFG_DIR_MEMBER_FUNCS(refresh_access_token_before_expiry, int, const char *) 156 | 157 | // ifdefs 158 | #ifdef USE_LIBJQ 159 | OIDC_CFG_DIR_MEMBER_FUNCS(userinfo_claims_expr, const char *) 160 | #endif 161 | 162 | // getters only 163 | OIDC_CFG_DIR_MEMBER_FUNC_GET_DECL(action_on_error_refresh, oidc_on_error_action_t) 164 | OIDC_CFG_DIR_MEMBER_FUNC_GET_DECL(pass_info_in, oidc_appinfo_pass_in_t) 165 | OIDC_CFG_DIR_MEMBER_FUNC_GET_DECL(pass_info_encoding, oidc_appinfo_encoding_t) 166 | OIDC_CFG_DIR_MEMBER_FUNC_GET_DECL(oauth_accept_token_in, oidc_oauth_accept_token_in_t) 167 | OIDC_CFG_DIR_MEMBER_FUNC_GET_DECL(unauthz_arg, const char *) 168 | 169 | // specials 170 | const char *OIDC_CFG_MEMBER_FUNC_NAME(accept_token_in_option, cfg_dir, get)(request_rec *r, const char *key); 171 | apr_byte_t OIDC_CFG_MEMBER_FUNC_NAME(unauth_expr, cfg_dir, is_set)(request_rec *r); 172 | const char *OIDC_CFG_MEMBER_FUNC_NAME(accept_oauth_token, cfg_dir, in2str)(apr_pool_t *pool, 173 | oidc_oauth_accept_token_in_t v); 174 | 175 | typedef struct oidc_dir_cfg_t oidc_dir_cfg_t; 176 | 177 | void *oidc_cfg_dir_config_create(apr_pool_t *, char *); 178 | void *oidc_cfg_dir_config_merge(apr_pool_t *, void *, void *); 179 | 180 | #endif // _MOD_AUTH_OPENIDC_CFG_DIR_H_ 181 | --------------------------------------------------------------------------------