├── 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 | [](https://github.com/OpenIDC/mod_auth_openidc/actions/workflows/build.yml)
2 | [
](https://openid.net/certification)
3 | [](https://github.com/OpenIDC/mod_auth_openidc/actions/workflows/codeql-analysis.yml)
4 | [](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 |
--------------------------------------------------------------------------------