pax_global_header00006660000000000000000000000064152723212620014514gustar00rootroot0000000000000052 comment=17c218e9e01920c282e84a022b7c2c380fc2c851 OpenVoxProject-trapperkeeper-webserver-8a905f4/000077500000000000000000000000001527232126200216545ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/.github/000077500000000000000000000000001527232126200232145ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/.github/dependabot.yml000066400000000000000000000005751527232126200260530ustar00rootroot00000000000000version: 2 updates: # raise PRs for gem updates - package-ecosystem: bundler directory: "/" schedule: interval: daily time: "13:00" open-pull-requests-limit: 10 # Maintain dependencies for GitHub Actions - package-ecosystem: github-actions directory: "/" schedule: interval: daily time: "13:00" open-pull-requests-limit: 10 OpenVoxProject-trapperkeeper-webserver-8a905f4/.github/release.yml000066400000000000000000000013231527232126200253560ustar00rootroot00000000000000--- # https://docs.github.com/en/repositories/releasing-projects-on-github/automatically-generated-release-notes changelog: exclude: labels: - duplicate - invalid - modulesync - question - skip-changelog - wont-fix - wontfix categories: - title: Breaking Changes 🛠 labels: - backwards-incompatible - title: New Features 🎉 labels: - enhancement - title: Bug Fixes ðŸ�› labels: - bug - title: Documentation Updates 📚 labels: - documentation - docs - title: Dependency Updates ⬆ï¸� labels: - dependencies - title: Other Changes labels: - "*" OpenVoxProject-trapperkeeper-webserver-8a905f4/.github/workflows/000077500000000000000000000000001527232126200252515ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/.github/workflows/lein-test.yaml000066400000000000000000000042651527232126200300500ustar00rootroot00000000000000--- name: lein_test on: pull_request: {} push: branches: - main permissions: contents: read jobs: run-lein-tests: name: lein test - Java ${{ matrix.java }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: java: [ '17', '21', '25' ] steps: - name: Check out repository code uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup java uses: actions/setup-java@b843ebf9b913146b38da2eaa7aeddf76074ae1ad # v6.1.0 with: distribution: temurin java-version: ${{ matrix.java }} - name: Install Clojure tools uses: DeLaGuardo/setup-clojure@6d46099eae24853c33c0482f2bb54edf4f1a4c74 # 13.7.0 with: cli: latest # Clojure CLI based on tools.deps lein: latest # Leiningen boot: latest # Boot.clj bb: latest # Babashka clj-kondo: latest # Clj-kondo cljstyle: latest # cljstyle zprint: latest # zprint - name: Run lein tests with dev test profile run: lein with-profile dev test - name: Run lein tests with fips profile run: lein with-profile fips test tests: if: always() needs: - run-lein-tests runs-on: ubuntu-24.04 name: Test suite steps: - name: Decide whether the needed jobs succeeded or failed uses: re-actors/alls-green@release/v1 with: jobs: ${{ toJSON(needs) }} automerge: name: Enable auto-merge if: github.event_name == 'pull_request' && (github.event.pull_request.user.login == 'dependabot[bot]' || github.event.pull_request.user.login == 'renovate[bot]') needs: - tests runs-on: ubuntu-24.04 permissions: contents: write pull-requests: write steps: - name: Enable auto-merge for PR env: GH_TOKEN: ${{ github.token }} PR_URL: ${{ github.event.pull_request.html_url }} PR_HEAD_SHA: ${{ github.event.pull_request.head.sha }} run: gh pr merge --auto --merge --match-head-commit "$PR_HEAD_SHA" "$PR_URL" OpenVoxProject-trapperkeeper-webserver-8a905f4/.github/workflows/prepare_release.yml000066400000000000000000000007611527232126200311360ustar00rootroot00000000000000--- name: 'Prepare Release' on: workflow_dispatch: inputs: version: description: 'Version to be released (e.g., 1.2.3)' required: true type: string permissions: {} jobs: prepare_release: uses: 'openvoxproject/shared-actions/.github/workflows/prepare_release.yml@main' with: version: ${{ inputs.version }} secrets: github_pat: ${{ secrets.OPENVOXBOT_COMMIT_AND_PRS }} ssh_private_key: ${{ secrets.OPENVOXBOT_SSH_PRIVATE_KEY }} OpenVoxProject-trapperkeeper-webserver-8a905f4/.github/workflows/release.yaml000066400000000000000000000007411527232126200275570ustar00rootroot00000000000000--- name: Release and publish package to clojars.org permissions: contents: write packages: write on: workflow_dispatch: jobs: release: uses: 'openvoxproject/shared-actions/.github/workflows/clojure_release.yml@main' secrets: github_pat: ${{ secrets.OPENVOXBOT_COMMIT_AND_PRS }} ssh_private_key: ${{ secrets.OPENVOXBOT_SSH_PRIVATE_KEY }} clojars_username: ${{ secrets.CLOJARS_USERNAME }} clojars_password: ${{ secrets.CLOJARS_PASSWORD }} OpenVoxProject-trapperkeeper-webserver-8a905f4/.gitignore000066400000000000000000000001241527232126200236410ustar00rootroot00000000000000.idea *.iml pom.xml target/ /.lein-failures /.bundle /.vendor /vendor /Gemfile.lock OpenVoxProject-trapperkeeper-webserver-8a905f4/CHANGELOG.md000066400000000000000000000260761527232126200235000ustar00rootroot00000000000000# Changelog All notable changes to this project will be documented in this file. ## [12.2.0](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.2.0) (2026-11-03) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.1.2...12.2.0) **Implemented enhancements:** - Remove unused flatland/ordered dependency [\#164](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/164) ([austb](https://github.com/austb)) ## [12.1.2](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.1.2) (2026-10-29) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.1.1...12.1.2) **Security fixes:** - Update jetty-version to v12.1.14 [\#155](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/155) ([renovate[bot]](https://github.com/apps/renovate)) **Merged pull requests:** - Add the Prepare Release workflow [\#157](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/157) ([nmburgan](https://github.com/nmburgan)) - Move the FIPS test profile to BouncyCastle FIPS 2.1 [\#153](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/153) ([nmburgan](https://github.com/nmburgan)) - Fix test run freeze in jetty service proxy unit test [\#140](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/140) ([jcharaoui](https://github.com/jcharaoui)) - Update minimum Leiningen version to 2.12.0 [\#132](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/132) ([corporate-gadfly](https://github.com/corporate-gadfly)) ## [12.1.1](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.1.1) (2026-08-11) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.1.0...12.1.1) ## [12.1.0](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.1.0) (2026-07-20) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.0.4...12.1.0) ## [12.0.4](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.0.4) (2026-07-11) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.0.3...12.0.4) ## [12.0.3](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.0.3) (2026-06-02) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.0.2...12.0.3) ## [12.0.2](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.0.2) (2026-05-13) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.0.1...12.0.2) **Merged pull requests:** - Force chunked transfer encoding to work around net-http bug [\#90](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/90) ([nmburgan](https://github.com/nmburgan)) ## [12.0.1](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.0.1) (2026-05-12) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/12.0.0...12.0.1) **Merged pull requests:** - move dev-resources to dev-only profile [\#89](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/89) ([austb](https://github.com/austb)) ## [12.0.0](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/12.0.0) (2026-05-11) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/10.0.0...12.0.0) **Breaking changes:** - Update to jetty 12 [\#59](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/59) ([austb](https://github.com/austb)) ## [10.0.0](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/10.0.0) (2026-05-09) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.8...10.0.0) **Merged pull requests:** - Changes for rename from trapperkeeper-webserver-jetty10 to trapperkeeper-webserver [\#80](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/80) ([nmburgan](https://github.com/nmburgan)) ## [1.1.8](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.8) (2026-04-25) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.7...1.1.8) ## [1.1.7](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.7) (2026-04-24) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.6...1.1.7) ## [1.1.6](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.6) (2026-04-24) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.5...1.1.6) **Implemented enhancements:** - CI: Add Java 25 support [\#73](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/73) ([bastelfreak](https://github.com/bastelfreak)) ## [1.1.5](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.5) (2026-04-13) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.4...1.1.5) ## [1.1.4](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.4) (2026-01-21) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.3...1.1.4) **Merged pull requests:** - Downgrade ring-core and ring-servlet to 1.14.2 [\#54](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/54) ([nmburgan](https://github.com/nmburgan)) ## [1.1.3](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.3) (2026-01-12) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.2...1.1.3) **Merged pull requests:** - Tell Renovate not to update Jetty major [\#52](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/52) ([nmburgan](https://github.com/nmburgan)) - Move version pins [\#49](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/49) ([nmburgan](https://github.com/nmburgan)) ## [1.1.2](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.2) (2026-01-10) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.1...1.1.2) ## [1.1.1](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.1) (2026-01-10) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.1.0...1.1.1) **Merged pull requests:** - Fix websocket test flakiness [\#42](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/42) ([nmburgan](https://github.com/nmburgan)) - Add logback version check [\#39](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/39) ([nmburgan](https://github.com/nmburgan)) - Remove errant nil values from deps [\#37](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/37) ([nmburgan](https://github.com/nmburgan)) - Remove clj-parent [\#9](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/9) ([nmburgan](https://github.com/nmburgan)) ## [1.1.0](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.1.0) (2026-01-03) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.0.19...1.1.0) **Implemented enhancements:** - add jdk21-fips-security [\#7](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/7) ([corporate-gadfly](https://github.com/corporate-gadfly)) - bump jetty version to 10.0.26 [\#1](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/1) ([corporate-gadfly](https://github.com/corporate-gadfly)) **Merged pull requests:** - Remove Janino, post-config-script setting, and update dependencies [\#8](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/8) ([nmburgan](https://github.com/nmburgan)) - README.md: Fix trailing whitespace & Use correct social link [\#6](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/6) ([bastelfreak](https://github.com/bastelfreak)) - Apply Vox Pupuli CI best practices [\#5](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/5) ([bastelfreak](https://github.com/bastelfreak)) ## [1.0.19](https://github.com/OpenVoxProject/trapperkeeper-webserver/tree/1.0.19) (2025-12-31) [Full Changelog](https://github.com/OpenVoxProject/trapperkeeper-webserver/compare/1.0.18...1.0.19) **Merged pull requests:** - CI and version: Changes for OpenVox namespacing [\#2](https://github.com/OpenVoxProject/trapperkeeper-webserver/pull/2) ([nmburgan](https://github.com/nmburgan)) ## unreleased changes ## 1.0.20 - update to Jetty 10.0.26 to resolve [CVE-2025-5115](https://github.com/advisories/GHSA-mmxm-8w33-wc4h) ## 1.0.19 - Migrate from Puppetlabs to OpenVoxProject ## 1.0.18 - update to clj-parent 7.3.5 - add pcp-client jetty dependencies to dependency list, to allow them to be centrally managed ## 1.0.17 - update jetty 10 to 10.0.20 to eliminate some race conditions - update clj-parent to the latest ## 1.0.16 - adds debug logging of Jetty server configuration before and after server(s) have been started ## 1.0.15 - cleans up accidental hard dependency on hato library in project.clj, hato is now only a dev dependency. ## 1.0.14 - ensure null `requestLog` in the MDCRequestHandler does not cause a null dereference. - enable logging for access log configuration ## 1.0.13 - ensure that absent log-access-configuration files don't prevent application from functioning correctly ## 1.0.12 - Reenable logback-access logging. This uses the "setRequestLog" function in jetty10 which guarantees that the request/response is settled prior to doing the logging. ## 1.0.11 - Remove default character encoding added in 1.0.8; add tests demonstrating overriding content-type - add customized SecureRequestCustomizer that makes SNI not required, and turn off host checking for SNI. This allows localhost connections to a server that doesn't have localhost in its cert specification. ## 1.0.10 - Empty tag ## 1.0.9 * add optional sni-required configuration setting ## 1.0.8 * set default encoding for ring handler responses to UTF-8 ## 1.0.7 * convert ring handler to using ServletContextHandler as previously used ContextHandler no longer supports the getRequestCharacterEncoding() function. ## 1.0.6 * route logging through a SLF4J Custom logger as logback-access no longer works with jetty10. This is a work around until full featured logging is developed. ## 1.0.5 * add the [`Response`](https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/Response.html) under the `:response` key in the request for ring-handlers. ## 1.0.4 * Added additional trace level logging to help diagnose issues * Removed some use of reflection by applying type metadata tags * Avoided some nil pointer dereferences in the disconnect case. ## 1.0.3 * Added Websocket event trace logging, removed logback 1.2.x version pins, clj-parent now specifies 1.3.x dependencies. ## 1.0.2 * Updated to Jetty 10.0.18, added ClosureLatchSyncer interface Jetty WebSocketAdapter object to sync closure of websocket client and server. ## 1.0.1 * Added ExecutionException handling when shutting down the server. Corrected WebSocketProtocol idle-timeout! function to produce a Duration. ## 1.0.0 * Initial release transitioning repository from Jetty 9 to Jetty 10, everything appears to be in working order but more production testing is needed and a subsequent release may be in short order. \* *This Changelog was automatically generated by [github_changelog_generator](https://github.com/github-changelog-generator/github-changelog-generator)* OpenVoxProject-trapperkeeper-webserver-8a905f4/Gemfile000066400000000000000000000003241527232126200231460ustar00rootroot00000000000000source ENV['GEM_SOURCE'] || 'https://rubygems.org' gem 'rake' group :release, optional: true do gem 'faraday-retry', '~> 2.1', require: false gem 'github_changelog_generator', '~> 1.18', require: false end OpenVoxProject-trapperkeeper-webserver-8a905f4/HISTORY.md000066400000000000000000000055471527232126200233520ustar00rootroot00000000000000## unreleased changes ## 1.0.20 - update to Jetty 10.0.26 to resolve [CVE-2025-5115](https://github.com/advisories/GHSA-mmxm-8w33-wc4h) ## 1.0.19 - Migrate from Puppetlabs to OpenVoxProject ## 1.0.18 - update to clj-parent 7.3.5 - add pcp-client jetty dependencies to dependency list, to allow them to be centrally managed ## 1.0.17 - update jetty 10 to 10.0.20 to eliminate some race conditions - update clj-parent to the latest ## 1.0.16 - adds debug logging of Jetty server configuration before and after server(s) have been started ## 1.0.15 - cleans up accidental hard dependency on hato library in project.clj, hato is now only a dev dependency. ## 1.0.14 - ensure null `requestLog` in the MDCRequestHandler does not cause a null dereference. - enable logging for access log configuration ## 1.0.13 - ensure that absent log-access-configuration files don't prevent application from functioning correctly ## 1.0.12 - Reenable logback-access logging. This uses the "setRequestLog" function in jetty10 which guarantees that the request/response is settled prior to doing the logging. ## 1.0.11 - Remove default character encoding added in 1.0.8; add tests demonstrating overriding content-type - add customized SecureRequestCustomizer that makes SNI not required, and turn off host checking for SNI. This allows localhost connections to a server that doesn't have localhost in its cert specification. ## 1.0.10 - Empty tag ## 1.0.9 * add optional sni-required configuration setting ## 1.0.8 * set default encoding for ring handler responses to UTF-8 ## 1.0.7 * convert ring handler to using ServletContextHandler as previously used ContextHandler no longer supports the getRequestCharacterEncoding() function. ## 1.0.6 * route logging through a SLF4J Custom logger as logback-access no longer works with jetty10. This is a work around until full featured logging is developed. ## 1.0.5 * add the [`Response`](https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/Response.html) under the `:response` key in the request for ring-handlers. ## 1.0.4 * Added additional trace level logging to help diagnose issues * Removed some use of reflection by applying type metadata tags * Avoided some nil pointer dereferences in the disconnect case. ## 1.0.3 * Added Websocket event trace logging, removed logback 1.2.x version pins, clj-parent now specifies 1.3.x dependencies. ## 1.0.2 * Updated to Jetty 10.0.18, added ClosureLatchSyncer interface Jetty WebSocketAdapter object to sync closure of websocket client and server. ## 1.0.1 * Added ExecutionException handling when shutting down the server. Corrected WebSocketProtocol idle-timeout! function to produce a Duration. ## 1.0.0 * Initial release transitioning repository from Jetty 9 to Jetty 10, everything appears to be in working order but more production testing is needed and a subsequent release may be in short order. OpenVoxProject-trapperkeeper-webserver-8a905f4/LICENSE000066400000000000000000000260751527232126200226730ustar00rootroot00000000000000Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright {yyyy} {name of copyright owner} Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. OpenVoxProject-trapperkeeper-webserver-8a905f4/Makefile000066400000000000000000000000441527232126200233120ustar00rootroot00000000000000include dev-resources/Makefile.i18n OpenVoxProject-trapperkeeper-webserver-8a905f4/README.md000066400000000000000000001006761527232126200231450ustar00rootroot00000000000000## Trapperkeeper Webserver Service This project provides a webserver service for use with the [trapperkeeper service framework](https://github.com/openvoxproject/trapperkeeper) To use this service in your trapperkeeper application, simply add this project as a dependency in your leiningen project file: [![Clojars Project](http://clojars.org/org.openvoxproject/trapperkeeper-webserver/latest-version.svg)](http://clojars.org/org.openvoxproject/trapperkeeper-webserver) Then add the webserver service to your [`bootstrap.cfg`](https://github.com/openvoxproject/trapperkeeper#bootstrapping) file, via: puppetlabs.trapperkeeper.services.webserver.jetty-service/jetty-service Note that the`:WebserverService` interface is intended to be agnostic to the underlying web server implementation. We also provide a [Jetty 9 version of the service](https://github.com/openvoxproject/trapperkeeper-webserver-jetty9), which can be used interchangeably with this one and will support older JDKs. You should only need to change your lein dependencies and your `bootstrap.cfg` file--no code changes. The web server is configured via the [trapperkeeper configuration service](https://github.com/openvoxproject/trapperkeeper#configuration-service); so, you can control various properties of the server (ports, SSL, etc.) by adding a `webserver` section to one of your Trapperkeeper configuration files, and setting various properties therein. For more info, see [Configuring the Webserver](doc/jetty-config.md). It is possible to configure both a single webserver or multiple webservers. The `webserver-service` currently supports web applications built using Clojure's [Ring](https://github.com/ring-clojure/ring) library and Java's Servlet API. There is also an experimental webserver service that supports loading ruby Rack applications via JRuby; for more info, see the [trapperkeeper-ruby](https://github.com/puppetlabs/trapperkeeper-ruby) project. ### Example code Four examples are included with this project: * A Ring example ([source code](./examples/ring_app)) * A Java servlet example ([source code](./examples/servlet_app)) * A WAR example ([source code](./examples/war_app)) * A multiserver configuration example ([source code](./examples/multiserver_app)) ### Service Protocol This is the protocol for the current implementation of the `:WebserverService`: ```clj (defprotocol WebserverService (add-context-handler [this base-path context-path] [this base-path context-path options]) (add-ring-handler [this handler path] [this handler path options]) (add-websocket-handler [this handlers path] [this handler path options]) (add-servlet-handler [this servlet path] [this servlet path options]) (add-war-handler [this war path] [this war path options]) (add-proxy-route [this target path] [this target path options]) (override-webserver-settings! [this overrides] [this server-id overrides]) (get-registered-endpoints [this] [this server-id]) (log-registered-endpoints [this] [this server-id]) (join [this] [this server-id]) ``` Here is a bit more info about each of these functions: #### `add-ring-handler` `add-ring-handler` takes two arguments: `[handler path]`. The `handler` argument is just a normal Ring application (the same as what you would pass to `run-jetty` if you were using the `ring-jetty-adapter`). The `path` is a URL prefix / context string that will be prepended to all your handler's URLs; this is key to allowing the registration of multiple handlers in the same web server without the possibility of URL collisions. So, for example, if your ring handler has routes `/foo` and `/bar`, and you call: ```clj (add-ring-handler my-app "/my-app") ``` Then your routes will be served at `/my-app/foo` and `my-app/bar`. You may specify `""` as the value for `path` if you are only registering a single handler and do not need to prefix the URL. In the handler, in the request passed to it, under the `:response` key is the [`Response`](https://www.eclipse.org/jetty/javadoc/jetty-10/org/eclipse/jetty/server/Response.html) that is used to deliver the response from the server. There is also a three argument version of this function which takes these arguments: `[handler path options]`. `options` is a map containing three optional keys. The first is `:server-id`, which specifies which server you want to add the ring-handler to. If `:server-id` is specified, the ring handler will be added to the server with id `:server-id`. If no `:server-id` is specified, or the two argument version is called, the ring handler will be added to the default server. Calling the two-argument version or leaving out `:server-id` will not work in a multiserver set-up if no default server is specified. The second optional argument is `:redirect-if-no-trailing-slash`. When set to `true`, all requests made to the endpoint at which the ring-handler was registered will, if no trailing slash is present, return a 302 redirect response to the same URL but with a trailing slash added. If the option is set to `false`, no redirect will occur, and the request will be routed through to the registered handler. This option defaults to `false`. The third optional argument is `:normalize-request-uri`. When set to `true`, the URI made available to the ring handler request map via the `:uri` key will have been "normalized". See the [Request URI Normalization] (#request-uri-normalization) section for more information on the normalization process. When set to `false` (the default value), the raw path component from the HTTP request URI will be the value for the `:uri` key. Here's an example of how to use the `:WebserverService`: ```clj (defservice MyWebService [[:WebserverService add-ring-handler]] ;; initialization (init [this context] (add-ring-handler my-app "/my-app") context)) ``` This would add your ring handler to the default server at endpoint "/my-app". Alternatively, if you did this: ```clj (defservice MyWebService [[:WebserverService add-ring-handler]] ;; initialization (init [this context] (add-ring-handler my-app "/my-app" {:server-id :foo}) context)) ``` it would add your ring handler to the server with id `:foo` at endpoint "/my-app", rather than the default server. *NOTE FOR COMPOJURE APPS*: If you are using compojure, it's important to note that compojure requires use of the [`context` macro](https://github.com/weavejester/compojure/wiki/Nesting-routes) in order to support nested routes. So, if you're not already using `context`, you will need to do something like this: ```clj (ns foo (:require [compojure.core :as c] ;;... )) (defservice MyWebService [[:WebserverService add-ring-handler]] ;; initialization (init [this svc-context] (let [context-path "/my-app" context-app (c/context context-path [] my-compojure-app)] (add-ring-handler context-app context-path)) svc-context)) ``` ##### Request URI Normalization The `:normalize-request-uri` setting, which can be provided in the `options` argument for an add handler call, controls whether or not the [path component](https://tools.ietf.org/html/rfc3986#section-3.3) from the HTTP request URI is normalized. The value for the setting is expected to be a boolean. When set to `false` (the default value), the "raw" path component will be used by the webserver when evaluating a request to the handler. When set to `true`, the path component that the webserver evaluates for a request to the handler will have been "normalized". For a Ring request handler, the "normalized" value (instead of the "raw" value) will be associated with the `:uri` key in the Ring request map. For a Servlet request handler, the "normalized" value (instead of the "raw" value) will be returned from a call made to the `getRequestURI` method on the `HttpServletRequest` object. The following steps, in order, are performed against the raw path component when the `:normalize-request-uri` setting is true: 1. URL (percent) decode the path, assuming any percent-encodings represent UTF-8 characters. For example: ``` /foo//bar/%2E%2E/ba%7A => /foo//bar/../baz ``` If a non-percent encoded semicolon character, U+003B, is found in the path during the percent decoding step, that character and all following characters will be removed from the resulting path, unless there is another forward slash, in which case the characters from the semicolon to the next forward slash (including the semicolon) will be removed. For example: ``` /foo//bar/%2E%2E/ba%7A;bim => /foo//bar/../baz ``` ``` /foo/bar;bar=chocolate/baz;baz=bim => /foo/bar/baz ``` Requests intending to include a semicolon in the path should percent-encode the semicolon. In this case, the server will preserve the semicolon after the decoding step. For example: ``` /foo//bar/%2E%2E/ba%7A%3Bbim => /foo//bar/../baz;bim ``` If the request has malformed content, e.g., partially-formed percent-encoded characters like '%A%B', an HTTP 400 (Bad Request) error will be returned. If the request has invalid % encoded UTF-8 characters, the path will be decoded as an ISO-8859-1 encoded string. 2. Check the percent-decoded path for any relative path segments ('..' or '.'). If one or more relative path segments are found, an HTTP 400 (Bad Request) error will be returned. For example, an error would be returned for any of the following paths: ``` . .. /foo//bar/../baz /foo//./bar/baz ``` The following paths would not be considered to contain relative paths: ``` /foo//bar/baz /foo//bar/.../baz /foo//bar/a.b/baz /foo//bar/a..b/baz ``` 3. Compact any repeated forward slash characters in a path. For example: ``` /foo//bar/baz => /foo/bar/baz /foo/bar////baz => /foo/bar/baz ``` The following example shows the result after normalization of a URI request path which includes repeated forward slash characters which have been percent-encoded: ``` /foo%2F%2Fbar/ba%7A => /foo/bar/baz ``` #### `add-context-handler` `add-context-handler` takes two arguments: `[base-path context-path]`. The `base-path` argument is a URL string pointing to a location containing static resources which are made accessible at the `context-path` URL prefix. For example, to make your CSS files stored in the `resources/css` directory available at `/css`: ```clj (defservice MyWebService [[:WebserverService add-context-handler]] ;; initialization (init [this context] (add-context-handler "resources/css" "/css") context)) ``` There is also a three argument version of the function which takes these arguments: `[base-path context-path options]`, where the first two arguments are the same as in the two argument version and `options` is a map containing five optional keys, `:server-id`, `:redirect-if-no-trailing-slash`, `:normalize-request-uri`, `:follow-links`, and `:context-listeners`. The value stored in `:server-id` specifies which server to add the context handler to, similar to how it is done in `add-ring-handler`. Again, like `add-ring-handler`, if this key is absent or the two argument version is called, the context handler will be added to the default server. Calling the two-argument version or leaving out `:server-id` will not work in a multiserver set-up if no default server is specified. The value stored in `:redirect-if-no-trailing-slash` is a boolean indicating whether or not to redirect when a request is made to this handler without a trailing slash, just like with `add-ring-handler`. Again, this defaults to false. The value stored in `:normalize-request-uri` is a boolean indicating whether or not the request URI should be normalized before it is made available to the handler. See the [Request URI Normalization](#request-uri-normalization) section for more information on the normalization process. The value stored in `:follow-links` is a boolean indicating whether or not symbolic links should be served. The service does NOT serve symbolic links by default. The value stored in `:context-listeners` is a list of objects implementing the [ServletContextListener] (http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContextListener.html) interface. These listeners are registered with the context created for serving the static content and receive notifications about the lifecycle events in the context as defined in the ServletContextListener interface. Of particular interest is the `contextInitialized` event notification as it provides access to the configuration of the context through the methods defined in the [ServletContext] (http://docs.oracle.com/javaee/7/api/javax/servlet/ServletContext.html) interface. This opens up wide possibilities for customizing the context - in an extreme case the context originally capable of serving just the static content can be changed through this mechanism to a fully dynamic web application (in fact this very mechanism is used in the [trapperkeeper-ruby] (https://github.com/puppetlabs/trapperkeeper-ruby) project to turn the context into a container for hosting an arbitrary ruby rack application - see [here] (https://github.com/puppetlabs/trapperkeeper-ruby/blob/master/src/clojure/puppetlabs/trapperkeeper/services/rack_jetty/rack_jetty_service.clj)). #### `add-servlet-handler` `add-servlet-handler` takes two arguments: `[servlet path]`. The `servlet` argument is a normal Java [Servlet](http://docs.oracle.com/javaee/7/api/javax/servlet/Servlet.html). The `path` is the URL prefix at which the servlet will be registered. There is also a three argument version of the function which takes these arguments: `[servlet path options]`, where the first two arguments are the same as in the two argument version and options is a map containing four optional keys, `:server-id`, `:redirect-if-no-trailing-slash`, `normalize-request-uri`, and `:servlet-init-params`. As in `add-ring-handler`, `:server-id` specifies which server to add the handler to. If `:server-id` is absent or the two-argument function is called, the servlet handler will be added to the default server. Calling the two-argument version or leaving out `:server-id` will not work in a multiserver set-up if no default server is specified. The value stored in `:redirect-if-no-trailing-slash` is a boolean indicating whether or not to redirect when a request is made to this handler without a trailing slash, just like with `add-ring-handler`. Again, this defaults to false. The value stored in `:normalize-request-uri` is a boolean indicating whether or not the request URI should be normalized before it is made available to the handler. See the [Request URI Normalization](#request-uri-normalization) section for more information on the normalization process. The value stored at the `:servlet-init-params` key is a map of servlet init parameters. For example, to host a servlet at `/my-app`: ```clj (ns foo ;; ... (:import [bar.baz SomeServlet])) (defservice MyWebService [[:WebserverService add-servlet-handler]] ;; initialization (init [this context] (add-servlet-handler (SomeServlet. "some config") "/my-app") context)) ``` For more information see the [example servlet app](examples/servlet_app). #### `add-websocket-handler` `add-websocket-handler` takes two arguments: `[handlers path]`. The `handlers` is a map of callbacks to invoke when handling a websocket session. The `path` is the URL prefix where this websocket servlet will be registered. The possible callbacks for the `handlers` map are: ```clj {:on-connect (fn [ws]) :on-error (fn [ws error]) :on-close (fn [ws status-code reason]) :on-text (fn [ws text]) :on-bytes (fn [ws bytes offset len])} ``` Querying data or sending messages over the websocket is supported by the functions of WebSocketProtocol protocol from the `puppetlabs.trapperkeeper.services.websocket-session` namespace: ```clj (connected? [this] "Returns a boolean indicating if the session is currently connected") (send! [this msg] "Send a message to the websocket client") (close! [this] [this code reason] "Close the websocket session") (remote-addr [this] "Find the remote address of a websocket client") (ssl? [this] "Returns a boolean indicating if the session was established by wss://") (peer-certs [this] "Returns an array of X509Certs presented by the ssl peer, if any") (request-path [this] "Returns the URI path used in the websocket upgrade request to the server")) ``` For example, to provide a simple websockets echo service as `/wsecho`: ```clj (ns foo (:require [puppetlabs.trapperkeeper.services.websocket-session :as ws-session])) (def echo-handlers {:on-text (fn [ws text] (ws-session/send! ws text))}) (defservice wsecho-webservice [[:WebserverService add-websocket-handler]] (init [this context] (add-websocket-handler echo-handlers "/wsecho") context)) ``` #### `add-war-handler` `add-war-handler` takes two arguments: `[war path]`. The `war` is the file path or the URL to a WAR file. The `path` is the URL prefix at which the WAR will be registered. For example, to host `resources/cas.war` WAR at `/cas`: ```clj (defservice cas-webservice [[:WebserverService add-war-handler]] (init [this context] (add-war-handler "resources/cas.war" "/cas") context)) ``` There is also a three-argument version that takes these parameters: `[war path options]`. `options` is a map containing three optional keys, `:server-id`, `:redirect-if-no-trailing-slash`, and `:normalize-request-uri`. As with `add-ring-handler`, this determines which server the handler is added to. If this key is absent or the two argument version is called, the handler will be added to the default server. Calling the two-argument version or leaving out `:server-id` will not work in a multiserver set-up if no default server is specified. The value stored in `:redirect-if-no-trailing-slash` is a boolean indicating whether or not to redirect when a request is made to this handler without a trailing slash, just like with `add-ring-handler`. Again, this defaults to false. The value stored in `:normalize-request-uri` is a boolean indicating whether or not the request URI should be normalized before it is made available to the handler. See the [Request URI Normalization](#request-uri-normalization) section for more information on the normalization process. #### `add-proxy-route` `add-proxy-route` is used to configure certain the server as a reverse proxy for certain routes. This function will accept two or three arguments: `[target path]`, or `[target path options]`. `path` is the URL prefix for requests that you wish to proxy. `target` is a map that controls how matching requests will be proxied; here are the keys required in the `target` map: * `:host`: required; a string representing the host or IP to proxy requests to. * `:port`: required; an integer representing the port on the remote host that requests should be proxied to. * `:path`: required; the URL prefix that should be prepended to all proxied requests. `options`, if provided, is a map containing optional configuration for the proxy route: * `:scheme`: optional; legal values are `:orig`, `:http`, and `:https`. If you specify `:http` or `:https`, then all proxied requests will use the specified scheme. The default value is `:orig`, which means that proxied requests will use the same scheme as the original request. * `:ssl-config`: optional; may be set to either `:use-server-config` (default) or to a map containing the keys `:ssl-cert`, `:ssl-key`, and `:ssl-ca-cert`, as well as the optional keys `:cipher-suites` and `:protocols`. If `:use-server-config`, then any proxied requests that use HTTPS will use the same SSL context/configuration that the web server is configured with. If you specify a map, then the entries must point to the PEM files that should be used for the SSL context. These keys have the same meaning as they do for the SSL configuration of the main web server. * `:rewrite-uri-callback-fn`: optional; a function to manipulate the rewritten target URI (e.g. change the port, or even change the entire URI) before Jetty continues on with the proxy. The function must accept two arguments, `[target-uri req]`. For more information, see [below](#rewrite-uri-callback-fn). * `:callback-fn`: optional; a function to manipulate the request object (e.g. to add additional headers) before Jetty continues on with the proxy. The function must accept two arguments, `[proxy-req req]`. For more information, see [below](#callback-fn). * `:request-buffer-size`: optional; an integer value to which to set the size of the request buffer used by the HTTP Client. This allows HTTP requests with very large cookies to go through, as a large cookie can cause the request buffer to overflow unless the size is increased. The default is 4096 bytes. * `:follow-redirects`: optional; a boolean that indicates whether or not the HttpClient created by a ProxyServlet should follow redirects. Defaults to `false`. * `:server-id`: optional; the id of the server to which to add the proxy handler. If absent, the handler will be added to the default server. If the two argument version of this function is called, the handler will also be added to the default server. Leaving out `:server-id` or calling the two argument version of this function will not work in a multiserver set-up if no default server is specified. * `:redirect-if-no-trailing-slash`: optional; a boolean indicating whether or not to redirect when a request is made to this proxy route without a trailing slash, as with `add-ring-handler`. Defaults to false. * `:idle-timeout`: optional; sets the maximum amount of time, measured in seconds, for the proxy to wait for a response from the upstream server. If no response is received within the time specified, then an HTTP 504 error is returned. If this option is not specified then a value of 30 seconds is used. Simple example: ```clj (defservice foo-service [[:WebserverService add-proxy-route]] (init [this context] (add-proxy-route {:host "localhost" :port 10000 :path "/bar"} "/foo") context)) ``` In this example, all incoming requests with a prefix of `/foo` will be proxied to `localhost:10000`, with a prefix of `/bar`, using the same scheme (HTTP/HTTPS) that the original request used, and using the SSL context of the main webserver. So, e.g., an HTTPS request to the main webserver at `/foo/hello-world` would be proxied to `https://localhost:10000/bar/hello-world`. A slightly more complex example: ```clj (defservice foo-service [[:WebserverService add-proxy-route]] (init [this context] (add-proxy-route {:host "localhost" :port 10000 :path "/bar"} "/foo" {:scheme :https :ssl-config {:ssl-cert "/tmp/cert.pem" :ssl-key "/tmp/key.pem" :ssl-ca-cert "/tmp/ca.pem"}}) context)) ``` In this example, all incoming requests with a prefix of `foo` will be proxied to `https://localhost:10000/bar`. We'll proxy using HTTPS even if the original request was HTTP, and we'll use the three pem files in `/tmp` to configure the HTTPS client, regardless of the SSL configuration of the main web server. #####`:rewrite-uri-callback-fn` This option lets you provide a function to manipulate the rewritten target URI. The function is called in the overridden implementation of [`rewriteURI`](http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/proxy/ProxyServlet.html#rewriteURI(javax.servlet.http.HttpServletRequest)) method after the target URI is computed. It must take two arguments, `[target-uri req]`, where `target-uri` is a [`URI`](http://docs.oracle.com/javase/7/docs/api/java/net/URI.html) and `req` is an [`HttpServletRequest`](http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html). `target-uri` will be modified and returned by the function. An example with a rewrite URI callback function: ```clj (defservice foo-service [[:WebserverService add-proxy-route]] (init [this context] (add-proxy-route {:host "localhost" :port 10000 :path "/bar"} "/foo" {:rewrite-uri-callback-fn (fn [target-uri req] (if-not (= "GET" (.getMethod req)) (URI. "http://localhost:11111/errors/unsupported-method") target-uri))}) context)) ``` In this example, all incoming requests with a method other than `GET` will be proxied to `http://localhost:11111/errors/unsupported-method`. #####`:callback-fn` This option lets you provide a function to manipulate the request object. The function will be passed to the [`customizeProxyRequest`](http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/proxy/ProxyServlet.html#customizeProxyRequest%28org.eclipse.jetty.client.api.Request,%20javax.servlet.http.HttpServletRequest%29) method. It must take two arguments, `[proxy-req req]`, where `proxy-req` is a [`Request`](http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/client/api/Request.html) and `req` is an [`HttpServletRequest`](http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html). `proxy-req` will be modified and returned by the function. An example with a callback function: ```clj (defservice foo-service [[:WebserverService add-proxy-route]] (init [this context] (add-proxy-route {:host "localhost" :port 10000 :path "/bar"} "/foo" {:callback-fn (fn [proxy-req req] (.header proxy-req "x-example" "baz"))}) context)) ``` In this example, all incoming requests with a prefix of `foo` will be proxied to `https://localhost:10000/bar`, using the same scheme (HTTP/HTTPS) that the original request used, and using the SSL context of the main webserver. In addition, a header `"x-example"` with the value `"baz"` will be added to the request before it is proxied, using the [`header`](http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/client/api/Request.html#header%28java.lang.String,%20java.lang.String%29) method. #### `override-webserver-settings!` `override-webserver-settings!` is used to override settings in the `webserver` section of the webserver service's config file. This function will accept one argument, `[overrides]`. `overrides` is a map which should contain a key/value pair for each setting to be overridden. The name of the setting to override should be expressed as a Clojure keyword. For any setting expressed in the service config which is not overridden, the setting value from the config will be used. For example, the webserver config may contain: ``` webserver { ssl-host: 0.0.0.0 ssl-port: 9001 ssl-cert: mycert.pem ssl-key: mykey.pem ssl-ca-cert: myca.pem } ``` Overrides may be supplied from the service using code like the following: ```clj (defservice foo-service [[:WebserverService override-webserver-settings!]] (init [this context] (override-webserver-settings! {:ssl-port 9002 :ssl-cert "myoverriddencert.pem" :ssl-key "myoverriddenkey.pem"}) context)) ``` For this example, the effective settings used during webserver startup would be: ```clj {:ssl-host "0.0.0.0" :ssl-port 9002 :ssl-cert "myoverriddencert.pem" :ssl-key "myoverriddenkey.pem" :ssl-ca-cert "myca.pem"} ``` The overridden webserver settings will be considered only at the point the webserver is being started -- during the start lifecycle phase of the webserver service. For this reason, a call to this function must be made during a service's init lifecycle phase in order for the overridden settings to be considered. Only one call from a service may be made to this function during application startup. If a call is made to this function after webserver startup or after another call has already been made to this function (e.g., from other service), a java.lang.IllegalStateException will be thrown. A three argument version is available which takes these parameters: `[server-id overrides]`. `server-id` is the id of the server for which you wish to override the settings. If the two argument version is called, they will be overridden for the default server. The one-argument version of this function will not work in a multiserver set-up if no default server is specified. #### `get-registered-endpoints` This function returns a map containing information on each URL endpoint registered by the Jetty service on the default server. Each key in the map is a URL endpoint, with each value being an array of maps containing information on each handler registered at that URL endpoint. The possible keys appearing in these maps are: * `:type`: The type of the registered endpoint. The possible types are `:context`, `:ring`, `:servlet`, `:war`, and `:proxy`. Returned for every endpoint. * `:base-path`: The base-path of a context handler. Returned only for endpoints of type `:context`. * `:context-listeners`: The context listeners for a context handler. Returned only for endpoints of type `:context` that have context listeners. * `:servlet`: The servlet for a servlet handler. Only returned for endpoints of type `:servlet`. * `:war-path`: The local path of the war registered by a war handler. Only returned for endpoints of type `:war`. * `:target-host`: The targeted host of a proxy request. Only returned for endpoints of type `:proxy`. * `:target-port`: The targeted port of a proxy request. Only returned for endpoints of type `:proxy`. * `:target-path`: The targeted prefix of a proxy request. Only returned for endpoints of type `:proxy`. The schema for the various types of handler maps can be viewed [here](https://github.com/openvoxproject/trapperkeeper-webserver/blob/master/src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj#L71-L96). There is also a version that takes one argument, `[server-id]`, which specifies which server for which you want to pull the endpoints. If this parameter is absent, the endpoints will be pulled for the default server. The no-argument version of this function will not work in a multiserver set-up if no default server is specified. #### `log-registered-endpoints` This function logs the data returned by `get-registered-endpoints` at the info level. There is a version of this function that takes a single argument, `[server-id]`. This specifies which server for which you want to log the endpoints. If this is absent, the endpoints registered on the default server will be logged. The no-argument version of this function will not work in a multiserver set-up if no default server is specified. #### `join` This function is not recommended for normal use, but is provided for compatibility with the `ring-jetty-adapter`. `ring-jetty-adapter/run-jetty`, by default, calls `join` on the underlying Jetty server instance. This allows your thread to block until Jetty shuts down. This should not be necessary for normal trapperkeeper usage, because trapperkeeper already blocks the main thread and waits for a termination condition before allowing the process to exit. However, if you do need this functionality for some reason, you can simply call `(join)` to cause your thread to wait for the Jetty server to shut down. There is another version of this function that takes a single argument, `[server-id]`. This is the id of the server you want to join. If this is not specified, then the default server will be joined. The no-argument version of this function will not work in a multi-server set-up if no default server is specified. ### Service lifecycle phases The Trapperkeeper service manipulates the Java Jetty code in the following ways during these lifecycle phases. #### `init` A `ContextHandlerCollection` is created during the `init` lifecycle which allows for consumers to use the `add-*-handler` and `add-proxy-route` functions, but the Jetty server itself has not started yet. This allows the service consumer to setup SSL keys and perform other operations needed before the server is started. #### `start` In the start lifecycle phase the Jetty server object is created, the `ContextHandlerCollection` is added to it, and the server is then started. Adding handlers after this phase should still work fine, but it is recommended that handlers be added during the consuming service's `init` phase. ## Webrouting Service This project provides a secondary Webrouting Service, which in many cases is preferable for use over the Webserver Service. Documentation is available for it [here](doc/webrouting-service.md). ## TrapperKeeper Webserver Service Test Utils This project provides some utility code for testing. Documentation on these test utils is available [here](doc/test-utils.md). ## Support GitHub issues and PRs are welcome! Additionally, drop us a line in [the Vox Pupuli Slack or IRC channel](https://voxpupuli.org/connect/). OpenVoxProject-trapperkeeper-webserver-8a905f4/Rakefile000066400000000000000000000031041527232126200233170ustar00rootroot00000000000000# frozen_string_literal: true begin require 'github_changelog_generator/task' rescue LoadError task :changelog do abort('Run `bundle install --with release` to install the `github_changelog_generator` gem.') end else GitHubChangelogGenerator::RakeTask.new :changelog do |config| config.header = <<~HEADER.chomp # Changelog All notable changes to this project will be documented in this file. HEADER config.user = 'OpenVoxProject' config.project = 'trapperkeeper-webserver' config.exclude_labels = %w[dependencies duplicate question invalid wontfix wont-fix modulesync skip-changelog] config.future_release = File.readlines('project.clj') .grep(/^\(defproject /).first[/"([^"]+)"/, 1] .sub(/-SNAPSHOT\z/, '') # The generated changelog starts with 1.0.19, the first release after the move to OpenVoxProject. config.since_tag = '1.0.18' config.release_branch = 'main' end end namespace :vox do desc 'Set the version in project.clj for the release' task 'version:bump:full', [:version] do |_, args| version = args[:version] abort 'You must provide a version.' if version.nil? || version.empty? project = File.read('project.clj') defproject = /^(\(defproject\s+\S+\s+)"[^"]+"/ abort 'Could not find the defproject version in project.clj' unless project.match?(defproject) File.write('project.clj', project.sub(defproject) { "#{Regexp.last_match(1)}\"#{version}\"" }) puts "Set the version in project.clj to #{version}" end end desc 'Prepare for a release' task 'release:prepare' => [:changelog] OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/000077500000000000000000000000001527232126200244425ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/Makefile.i18n000066400000000000000000000141311527232126200266600ustar00rootroot00000000000000# -*- Makefile -*- # This file was generated by the i18n leiningen plugin # Do not edit this file; it will be overwritten the next time you run # lein i18n init # # The name of the package into which the translations bundle will be placed BUNDLE=puppetlabs.trapperkeeper_webserver # The name of the POT file into which the gettext code strings (msgid) will be placed POT_NAME=trapperkeeper-webserver.pot # The list of names of packages covered by the translation bundle; # by default it contains a single package - the same where the translations # bundle itself is placed - but this can be overridden - preferably in # the top level Makefile PACKAGES?=$(BUNDLE) LOCALES=$(basename $(notdir $(wildcard locales/*.po))) BUNDLE_DIR=$(subst .,/,$(BUNDLE)) BUNDLE_FILES=$(patsubst %,resources/$(BUNDLE_DIR)/Messages_%.class,$(LOCALES)) FIND_SOURCES=find src -name \*.clj # xgettext before 0.19 does not understand --add-location=file. Even CentOS # 7 ships with an older gettext. We will therefore generate full location # info on those systems, and only file names where xgettext supports it LOC_OPT=$(shell xgettext --add-location=file -f - /dev/null 2>&1 && echo --add-location=file || echo --add-location) LOCALES_CLJ=resources/locales.clj define LOCALES_CLJ_CONTENTS { :locales #{$(patsubst %,"%",$(LOCALES))} :packages [$(patsubst %,"%",$(PACKAGES))] :bundle $(patsubst %,"%",$(BUNDLE).Messages) } endef export LOCALES_CLJ_CONTENTS i18n: msgfmt # Update locales/.pot update-pot: locales/$(POT_NAME) locales/$(POT_NAME): $(shell $(FIND_SOURCES)) | locales @tmp=$$(mktemp $@.tmp.XXXX); \ $(FIND_SOURCES) \ | xgettext --from-code=UTF-8 --language=lisp \ --copyright-holder='Puppet ' \ --package-name="$(BUNDLE)" \ --package-version="$(BUNDLE_VERSION)" \ --msgid-bugs-address="docs@puppet.com" \ -k \ -kmark:1 -ki18n/mark:1 \ -ktrs:1 -ki18n/trs:1 \ -ktru:1 -ki18n/tru:1 \ -ktrun:1,2 -ki18n/trun:1,2 \ -ktrsn:1,2 -ki18n/trsn:1,2 \ $(LOC_OPT) \ --add-comments --sort-by-file \ -o $$tmp -f -; \ sed -i.bak -e 's/charset=CHARSET/charset=UTF-8/' $$tmp; \ sed -i.bak -e 's/POT-Creation-Date: [^\\]*/POT-Creation-Date: /' $$tmp; \ rm -f $$tmp.bak; \ if ! diff -q -I POT-Creation-Date $$tmp $@ >/dev/null 2>&1; then \ mv $$tmp $@; \ else \ rm $$tmp; touch $@; \ fi # Run msgfmt over all .po files to generate Java resource bundles # and create the locales.clj file msgfmt: $(BUNDLE_FILES) $(LOCALES_CLJ) clean-orphaned-bundles # Force rebuild of locales.clj if its contents is not the the desired one. The # shell echo is used to add a trailing newline to match the one from `cat` ifneq ($(shell cat $(LOCALES_CLJ) 2> /dev/null),$(shell echo '$(LOCALES_CLJ_CONTENTS)')) .PHONY: $(LOCALES_CLJ) endif $(LOCALES_CLJ): | resources @echo "Writing $@" @echo "$$LOCALES_CLJ_CONTENTS" > $@ # Remove every resource bundle that wasn't generated from a PO file. # We do this because we used to generate the english bundle directly from the POT. .PHONY: clean-orphaned-bundles clean-orphaned-bundles: @for bundle in resources/$(BUNDLE_DIR)/Messages_*.class; do \ locale=$$(basename "$$bundle" | sed -E -e 's/\$$?1?\.class$$/_class/' | cut -d '_' -f 2;); \ if [ ! -f "locales/$$locale.po" ]; then \ rm "$$bundle"; \ fi \ done resources/$(BUNDLE_DIR)/Messages_%.class: locales/%.po | resources msgfmt --java2 -d resources -r $(BUNDLE).Messages -l $(*F) $< # Use this to initialize translations. Updating the PO files is done # automatically through a CI job that utilizes the scripts in the project's # `bin` file, which themselves come from the `clj-i18n` project. locales/%.po: | locales @if [ ! -f $@ ]; then \ touch $@ && msginit --no-translator -l $(*F) -o $@ -i locales/$(POT_NAME); \ fi resources locales: @mkdir $@ help: $(info $(HELP)) @echo .PHONY: help define HELP This Makefile assists in handling i18n related tasks during development. Files that need to be checked into source control are put into the locales/ directory. They are locales/$(POT_NAME) - the POT file generated by 'make update-pot' locales/$$LANG.po - the translations for $$LANG Only the $$LANG.po files should be edited manually; this is usually done by translators. You can use the following targets: i18n: refresh all the files in locales/ and recompile resources update-pot: extract strings and update locales/$(POT_NAME) locales/LANG.po: create translations for LANG msgfmt: compile the translations into Java classes; this step is needed to make translations available to the Clojure code and produces Java class files in resources/ endef # @todo lutter 2015-04-20: for projects that use libraries with their own # translation, we need to combine all their translations into one big po # file and then run msgfmt over that so that we only have to deal with one # resource bundle OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/000077500000000000000000000000001527232126200257075ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/000077500000000000000000000000001527232126200270465ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/000077500000000000000000000000001527232126200276475ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs/000077500000000000000000000000001527232126200307675ustar00rootroot00000000000000ca-master-intermediate-and-root.pem000066400000000000000000000051211527232126200374570ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs-----BEGIN CERTIFICATE----- MIID3zCCAsegAwIBAgIBAjANBgkqhkiG9w0BAQUFADBJMRAwDgYDVQQDDAdSb290 IENBMRowGAYDVQQLDBFTZXJ2ZXIgT3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBs ZSBPcmcsIExMQzAeFw0xNDA0MDgwMTI1MzdaFw0zNDA0MDMwMTI1MzdaMH4xJDAi BgNVBAMTG0ludGVybWVkaWF0ZSBDQSAobWFzdGVyLWNhKTEfMB0GCSqGSIb3DQEJ ARYQdGVzdEBleGFtcGxlLm9yZzEZMBcGA1UEChMQRXhhbXBsZSBPcmcsIExMQzEa MBgGA1UECxMRU2VydmVyIE9wZXJhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTgKLGBkExFRXrQJn/lHE4XHkN2nXwJpS+y8bWqHiBdq5eZ8D2 UAILOBaALeQN/1d1J4yrh6w/YK+gRtCLn+CslR+9NW4AgShALi+r26DK9ZRk4F7V Dk4yEjNpmTyVRyP8w7iZwasZdyK04xAhj+yEInz29SLxmh1jddts/rjqLMZW/s0S T+E9XSEDYNVprC5VuYutUuHKah7AYSp07FHNsqDg+y+vCRezSqbrHrGpTwMupVmD 2ObsSJntghsLzPwjSGhbo6e8C/TDwrPtm6az9TPKbsUrqjdvyZcSfc5Q6OgExNhg zWQkk5PqFOESsQSBfOOn2eqfqBXHUnH9PCNTAgMBAAGjgZwwgZkweQYDVR0jBHIw cIAUFq+AJeP66ki/kTNmAf1R7yRnTGOhTaRLMEkxEDAOBgNVBAMMB1Jvb3QgQ0Ex GjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQKDBBFeGFtcGxlIE9y ZywgTExDggkAsbkEcvsRJ+MwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAC4keJ+jeGh7/EWwsCKollYW7H4aSjPu/Ufe38hH pEER9FyCqJ0jo+MabOx8l1F5ySNWngB0qbJuA/kiV2gJ1bQ+mE2TN88x6Sz12eol ifhFU0PazGdpNQRhpQxbwJ7tFC3Z8WrHEcVqP9iicNWqSI/QkqXsCk4Zyezpx28W sqHylf1CiBOU45FJdDXRg80mk6WOpNZR8HIUdqQLQDXz0FfXeFKmVteatmc/yrGG 5iHzMkH4Vz5laBjin9s1p+O8Z7+cWtJNWfXaULAEecZQ6CZ3V1OVOjhsrL28iF7C kx01rSrsxaFclDalJVmKmO2spHvNmQTlWD6jm5d94WaRyXU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZTCCAk2gAwIBAgIJALG5BHL7ESfjMA0GCSqGSIb3DQEBBQUAMEkxEDAOBgNV BAMMB1Jvb3QgQ0ExGjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQK DBBFeGFtcGxlIE9yZywgTExDMB4XDTE0MDQwODAxMjUzNloXDTM0MDQwMzAxMjUz NlowSTEQMA4GA1UEAwwHUm9vdCBDQTEaMBgGA1UECwwRU2VydmVyIE9wZXJhdGlv bnMxGTAXBgNVBAoMEEV4YW1wbGUgT3JnLCBMTEMwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDFDXbR+00AwXM+HuMIpw8eVWBzQWBqDCYkX3IvYRGj+w9y 7AitrN+J0MZE3pbaRvlH5wU7MShFOmT0k/B/wrylW4W5G/iAtd2ZnXicBPrA9zDU eHJftQxR7+Qjmsc1BqVf43PUlQITpn1APgXDzPJdk9XbRWEsIycuXkwTXzVND0U5 z3dGS/oh9yMim0DnF2oQ+gTFA9n17xOD5hBN80U3fn4DXtcFGbtXOj6zBHsxgLCi leif2AB1oAaZ0lqkwk6Se0rFd3zafYLDAwCPCWlZSfkQ0C/W7WYx07PDRxSYs1H6 Viz2uHwqzyD6elxvJBGcrLdvDqTLL+w0ag3yMPWbAgMBAAGjUDBOMB0GA1UdDgQW BBQWr4Al4/rqSL+RM2YB/VHvJGdMYzAfBgNVHSMEGDAWgBQWr4Al4/rqSL+RM2YB /VHvJGdMYzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC/sFnu1TIr L6HhTft5aUaeLuO/329cDUHxlUppGRYrctkZvYK4b8TBi2BD+tcwRKS1kh4nrQhr xaBO+oUmyJeNwEPk40trzusV9N9tfqw8drBBXEVZGxrYRYovq/RqLfUQ224EF3z0 r74dAWL0R80PvVzeJfUsUw0KYgskfLzP5QSW1rrJnutfYP95EMV4yWyrNqnDko3M v7XENh0TMEolMxPZ+X3TqT6Q0j4aM8njswObyeABslt+nC6nLfgBvgDaSvEULPL6 u5aWNxp9WudGqGBvHoR6OXdZDRCzWSz52jnvXiZE4E0VnqsWxCmjDGECke4TRoMU rtMLavKgCsIe -----END CERTIFICATE----- ca-master-intermediate.pem000066400000000000000000000025731527232126200357460ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs-----BEGIN CERTIFICATE----- MIID3zCCAsegAwIBAgIBAjANBgkqhkiG9w0BAQUFADBJMRAwDgYDVQQDDAdSb290 IENBMRowGAYDVQQLDBFTZXJ2ZXIgT3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBs ZSBPcmcsIExMQzAeFw0xNDA0MDgwMTI1MzdaFw0zNDA0MDMwMTI1MzdaMH4xJDAi BgNVBAMTG0ludGVybWVkaWF0ZSBDQSAobWFzdGVyLWNhKTEfMB0GCSqGSIb3DQEJ ARYQdGVzdEBleGFtcGxlLm9yZzEZMBcGA1UEChMQRXhhbXBsZSBPcmcsIExMQzEa MBgGA1UECxMRU2VydmVyIE9wZXJhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTgKLGBkExFRXrQJn/lHE4XHkN2nXwJpS+y8bWqHiBdq5eZ8D2 UAILOBaALeQN/1d1J4yrh6w/YK+gRtCLn+CslR+9NW4AgShALi+r26DK9ZRk4F7V Dk4yEjNpmTyVRyP8w7iZwasZdyK04xAhj+yEInz29SLxmh1jddts/rjqLMZW/s0S T+E9XSEDYNVprC5VuYutUuHKah7AYSp07FHNsqDg+y+vCRezSqbrHrGpTwMupVmD 2ObsSJntghsLzPwjSGhbo6e8C/TDwrPtm6az9TPKbsUrqjdvyZcSfc5Q6OgExNhg zWQkk5PqFOESsQSBfOOn2eqfqBXHUnH9PCNTAgMBAAGjgZwwgZkweQYDVR0jBHIw cIAUFq+AJeP66ki/kTNmAf1R7yRnTGOhTaRLMEkxEDAOBgNVBAMMB1Jvb3QgQ0Ex GjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQKDBBFeGFtcGxlIE9y ZywgTExDggkAsbkEcvsRJ+MwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAC4keJ+jeGh7/EWwsCKollYW7H4aSjPu/Ufe38hH pEER9FyCqJ0jo+MabOx8l1F5ySNWngB0qbJuA/kiV2gJ1bQ+mE2TN88x6Sz12eol ifhFU0PazGdpNQRhpQxbwJ7tFC3Z8WrHEcVqP9iicNWqSI/QkqXsCk4Zyezpx28W sqHylf1CiBOU45FJdDXRg80mk6WOpNZR8HIUdqQLQDXz0FfXeFKmVteatmc/yrGG 5iHzMkH4Vz5laBjin9s1p+O8Z7+cWtJNWfXaULAEecZQ6CZ3V1OVOjhsrL28iF7C kx01rSrsxaFclDalJVmKmO2spHvNmQTlWD6jm5d94WaRyXU= -----END CERTIFICATE----- OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs/ca-root.pem000066400000000000000000000023251527232126200330400ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIDZTCCAk2gAwIBAgIJALG5BHL7ESfjMA0GCSqGSIb3DQEBBQUAMEkxEDAOBgNV BAMMB1Jvb3QgQ0ExGjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQK DBBFeGFtcGxlIE9yZywgTExDMB4XDTE0MDQwODAxMjUzNloXDTM0MDQwMzAxMjUz NlowSTEQMA4GA1UEAwwHUm9vdCBDQTEaMBgGA1UECwwRU2VydmVyIE9wZXJhdGlv bnMxGTAXBgNVBAoMEEV4YW1wbGUgT3JnLCBMTEMwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDFDXbR+00AwXM+HuMIpw8eVWBzQWBqDCYkX3IvYRGj+w9y 7AitrN+J0MZE3pbaRvlH5wU7MShFOmT0k/B/wrylW4W5G/iAtd2ZnXicBPrA9zDU eHJftQxR7+Qjmsc1BqVf43PUlQITpn1APgXDzPJdk9XbRWEsIycuXkwTXzVND0U5 z3dGS/oh9yMim0DnF2oQ+gTFA9n17xOD5hBN80U3fn4DXtcFGbtXOj6zBHsxgLCi leif2AB1oAaZ0lqkwk6Se0rFd3zafYLDAwCPCWlZSfkQ0C/W7WYx07PDRxSYs1H6 Viz2uHwqzyD6elxvJBGcrLdvDqTLL+w0ag3yMPWbAgMBAAGjUDBOMB0GA1UdDgQW BBQWr4Al4/rqSL+RM2YB/VHvJGdMYzAfBgNVHSMEGDAWgBQWr4Al4/rqSL+RM2YB /VHvJGdMYzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC/sFnu1TIr L6HhTft5aUaeLuO/329cDUHxlUppGRYrctkZvYK4b8TBi2BD+tcwRKS1kh4nrQhr xaBO+oUmyJeNwEPk40trzusV9N9tfqw8drBBXEVZGxrYRYovq/RqLfUQ224EF3z0 r74dAWL0R80PvVzeJfUsUw0KYgskfLzP5QSW1rrJnutfYP95EMV4yWyrNqnDko3M v7XENh0TMEolMxPZ+X3TqT6Q0j4aM8njswObyeABslt+nC6nLfgBvgDaSvEULPL6 u5aWNxp9WudGqGBvHoR6OXdZDRCzWSz52jnvXiZE4E0VnqsWxCmjDGECke4TRoMU rtMLavKgCsIe -----END CERTIFICATE----- OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs/ca.pem000066400000000000000000000034151527232126200320600ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFCTCCAvGgAwIBAgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBw ZXQgQ0E6IGxvY2FsaG9zdDAeFw0xOTAyMjUxNDM1MzRaFw0yOTAyMjIxNDM1MzRa MB8xHTAbBgNVBAMMFFB1cHBldCBDQTogbG9jYWxob3N0MIICIjANBgkqhkiG9w0B AQEFAAOCAg8AMIICCgKCAgEA5vYnoJ85k6qcUFzWFOr9MN2ZWFlgA6nB0Adfm8Yg ovg963NrauwTcoPqbfGhi53A8RWc5GT5x1OSjxQW/PAGGfGg3aHZuQMClYWsauod CYG6YgG49WGZODCHZ+TbHMN1pNV+6S+tnZbUtfVKsN347XyHCyrymmb/OQNAxPyO /76dDR4dB7kWKP4KMMOgDAnA+WDpD1d9/UfBPVZtw/sTyjeJGEOZqSXQW93PKumJ 9/DS4azsUMR1JwJA67yWffoHb6sL7QSAQEfp17gDs9asIzITZPPyHNslmY55zaSW EslzFGqPvB7ugUbqH0rjp2TjQ/9Nw7ZKBxukFB9cBUr7v21D2Of2SHQorzRe9lXO wO3BYEt/viypktDnH42qAeoLHDK1ay9ugByTm4ARj14CjslpkEKflk9t9XwUR3ku Uaj3w+Y5ItZXFBxns1OQpDt3bMhJFemj7MxkZXt8tvWlUMKVmCUqbnG1eDdTF4Vd OovdacMDpvKg438I8MCjaHQf90qIp8MaOjdfSoKBCQi6AP7cpjB+x9xhEuetPYcb /bNjV1OFo4h77XJ+lIH58HBpEG0zkqhtS7JqICIzp3GK7ZG3bhfKKJz0Qr4ISxI0 YsYWdmsG38SyMwcomMy4WoLiuQF2QusBSHwBS+p5qQyNkJmXEy8KSQmrrIB/bkiS mgkCAwEAAaNQME4wHQYDVR0OBBYEFFnLcPS9AaIG7eaeCCryOIRkRGhfMB8GA1Ud IwQYMBaAFFnLcPS9AaIG7eaeCCryOIRkRGhfMAwGA1UdEwQFMAMBAf8wDQYJKoZI hvcNAQELBQADggIBADGlyXkzoGImCCg6jnTmUUUW5ngFA6Z//EbiNIMohkkR8YnO NZ+Y1qwy2KJwwT8UwB4n6QAI1hgFoBplqVpmXfoXBUiMsfLiA0pGAMQLdnp9VN6/ ukGNQOg7TH8HqvQy4WWJw7rgQGnHyqtOLOYPnYWOy5iR7QKbUDULmSB053t6QiyX SCTVLgjHuzmvAlUG2K4EaG4KyWtTVFKB7iBz+7+9NkWlRm3sh6iq4FkDVGyKm0Vk b/6se4FWAPiTyVUKkcj+34Ca8yicxXhBCw2pUTedctOH2cQXOsgC9Ur5AXrd/53V jXaNlwBmGnxZH4NCV5igS2on9Bv754ExZiXABLghRMzHZuKZycwyT8ahdo7lYF87 S2PlbBvvmaRaONv9utmHsbh3OCUPBCQl5hHNZhptx4wU/1z+WKa/dh38F7hI0qkV 8WBDGcB2s93El+NWtTf8cx4tzc66A+/ihlEPhXs0hcRwDfeqftmqLULLQxpHkDF/ 3z3764VrIe9ftKJA5RgikaANzMjO9+3xTnr6fdKFHYJs7LYGay0ONVxQlOY/Y/qX iDLHaPgwpe2FQIkD5YsfiK+UoUtRNMd1LC7DX7CNu9PDL/cjtGsCvzIY1oLfDWCK vYn2UUu49nTnHTnn1Y2mX0d9hIN3QBHqFAuR8PCwXb/vu5y5BdXlvMk6TLPD -----END CERTIFICATE----- localhost-compromised.pem000066400000000000000000000037611527232126200357310ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs-----BEGIN CERTIFICATE----- MIIFsTCCA5mgAwIBAgIBBDANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBw ZXQgQ0E6IGxvY2FsaG9zdDAeFw0xNDA0MjgyMTExMzNaFw0xOTA0MjgyMTExMzNa MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC AgoCggIBALlZ0tk6PCNVZcdwS8BYD1g8ZFLJqrrsqdHaaLLBZDXSW9lhrumDUi55 cpxkwKwg4E+BZTXliGFQLznS/0r4yOp00diMYfik6ecl0prut/H3RUcm2EXENqun qZeExlSArFy6c6ppzlt8pFb09bwp/nRSZ5DkGqssVWlsmAGPu0qLNrZJLkStFe7H Y56YUlolGm4gJRNjRo4fFxa8o4nclk6kSS/u6GP0omXv7qIhIWsP1plMeOEnhArI oeNX1l9pyb1scW0a4t9x/IBuayF3o4/56KOvysVmVfaWlSkHKYWWpmuh0SeIIhbw Oy/ZizweC1C7GlygTujOciLAGkSU/P975qBbQGftu0actbmDOoLTYOPEXHTy1SUV cSrwLzifg05dwEqlLApwPjdPHSuc3Rk6ZsxnQM6RpJ78DFULLSYzyhdkgg89quga QlFeqqKqyamVyJrpgtf4K0Zi2hlUY29qLDtuTlm+Psaf5hC9ihc4ZFxlmvOCTg+J 3VY7GkFSG0XjVMDWdfku8Kmgteugpjrw5/Ox20H9wyxQ21Oo35wOOx60slxfg+YV eYp9gbAVN4czoNyGsjf9JX92jifYtyZyzQfRvWYD0eBVvrPpm5JA0QKNZ/94GW/m sATLFFmGMWpfvHaHqHkylmV1EigZlp5nDFQjID/SLdsFJ3VT6xW/AgMBAAGjggEB MIH+MDUGCWCGSAGG+EIBDQQoUHVwcGV0IFJ1YnkvT3BlblNTTCBJbnRlcm5hbCBD ZXJ0aWZpY2F0ZTBFBgNVHREEPjA8ghlKZXJlbXlzLU1hY0Jvb2stUHJvLmxvY2Fs gglsb2NhbGhvc3SCBnB1cHBldIIMcHVwcGV0LmxvY2FsMA4GA1UdDwEB/wQEAwIF oDAgBgNVHSUBAf8EFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIw ADAdBgNVHQ4EFgQUWS8hsFK9ol/oZGnV633lUiTP8cAwHwYDVR0jBBgwFoAUWctw 9L0Bogbt5p4IKvI4hGREaF8wDQYJKoZIhvcNAQELBQADggIBABO4zPGBGrnsGMtt RlQJrau/1Kr5rWz/TJGS3RQjpdXTVI0z5ebLGamsKDaOCmPpq8SVjCv2M+yuUm2O mf51WN+A2906ITTxPD7QhVGp7WRJDMbcr3g9j3VtijDL7ogZcmEC4cUhHwnVDVMG qTubriSHYlUa5bmoZ5nKRPd1rPwU9/jrZUXesf0SqV1W+p+bUIH4aid7U5nkE67T jvqtoouyI2DtUUE/7LOtkKFxXZSKE3gJ5SGfc0ENZmS6+YjMr5YQkreWLys7Cwem 430QHE35TvdgqGYtzit/t05473+CVUb9vhy7bJwLGdG/wCnCmuVGNuGVccxRR+vz RuL9IJ8wsXPdVxdksA+VzUxDnsPXOFQRIPpzqF1bMWYoWZV0IgRzkmsYH/zwi7qy QHsxXWQP0Kflx95Nc5BNZWZjKeBZx41Vk7+82YGS83YNMihOX1iwt/sdt29vrxs9 uUXFFKcoKrgKcO8PlqP8wbqluO99nGzw3U8dvXyPpTe0tRpnOIfRiNZlwfXVJbTS ZhbgCX2ro7eaENLAgM98rew2toP8bxgh5E5npRizilOSfARu9aY4hUB1wsY9VYUi NtHNBy6jjg5XsYWkfjm448Ev+MW0hy6Iq+53MM+QsMliK3UueImmV5aJf2z7lrvC 6+idiQs4I/GfVleruewU/+EZBX02 -----END CERTIFICATE----- OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs/localhost.p12000066400000000000000000000122451527232126200333070ustar00rootroot000000000000000‚¡0‚g *†H†÷  ‚X‚T0‚P0‚ ‡ *†H†÷  ‚ x0‚ t0‚ m *†H†÷ 0 *†H†÷  0\(w¨� H‡€‚ @Bõì\k„µ9!�ÄRû™³ RÒ«8œiŽ€m�»Í–ÃC8Úéq¸¥QŶº´¼gbSÔæã~esÔH\Ú!ÿËg“kLÜ'üh±¢©Q‚}ód˜Ð·æö¦m:<ù@Ëxe–ý'Ä”Ù$.k© 6ʆ˜E 1ôì2™*œÖ_{у7š¢¶p8×�-8mu˜åûòýðáÂí‡ËÈzVGÒ¨J9â½Ó?è›-Vsºf¼½“ÿæÜ“ ð{v;TŠÏæ5‚�ží#ÿjci5–2 !�š‹ %èóx¬I[^c€G_ƒô4xc€ãz¿‚†ï\¨"k;Ò%ý3¿$�.SÅù¶$GÝæõÝy‡�§”Òá/Dä.³×†®l¨ ü8žþ–¾Faz i›pì+F%�þ3U'�7ÍëÀél¶°§sT a¥ä~¼)SÂÍÛLï” 7a™éf@U%*½àO¥>’�êK}1š¦Ðr2±D)¡Pzz¤£òÄ[U*zäɃê$&Gý¢Ï*깩�R ËUÏ´9½sæ¨G#Lè6q– µÑ‰6 ·1×ÁçükkÒ›¹3þ¾�x"„Õžh¥¥äcé—­ÆÃúÐ÷qÈ2ЦÁp^Wë–o'ƒm�.»*c�(z4ÈÍŸ„£¹ÕÙF’V¨Ã`Dï¥J¡ƒÆïÙbXP]‚jf(Cä©0ˆw²;b%”;c1Ž�ç‘Ä*ßõ¢‰Uo9XÁ·q6&GA›Yš‘žõHåD¡r»Î§Ž®ðŸøyuš1ÉqJ¸í¿Ó >oòÙ50GˆòAÀi_öb´7�ОĒØáãh6M*ÍÒYBÄ9]\Ì�ج }¦M¾$Þ. 6\ÍY.™€ÖÛÏ{«öfØ*¸.ÜaûÄŠØ7 ë_íF˜<Nµ]Ò¨–@„Äšˆ0�¬ØÈ})ÿ;< ˜©T�çUS.>кM¤cƒÏôîëKç<»#S")ÜJ„È$M �K*D¨—ÂR&Æý,ÑtµKž-¨-içÜ!`®›ÕcP Æ?tD‹wH[gmQÇÀ鿱U¡G#÷«ÜØk‰ìV_¥Ëÿýß8ÈV±0-ëB”xÞøf1OËÏog¥*ŽÙÛwí˲†EÓ¹{ §O�—r5¯ýZ“?rQr¼Ð–¹�…‰±¨ÃÆqKF\õä­5êjD燻(ר\t'à‚áÞõº¾Ø>é½êÓ-²e[‡i8€$ö”‚´‡O˜®ßžx¦íì¶oÁÅ£ö•uÇ+8-~#t £bî~`_k²Žè.}Aàp\&q8˜—MP™à9|—êŠ~Š\Ìss§£„%nH7‘]ûƃÓoïÓ-�—Âþ:N}$,ë4eÉÀ¹ã ”&­ìÐ>~9ú/l^»¶+ÑÞ™x¥W‚…–ƒGñìÎå"ÿꫵ–›‚ Œ8x¢ìÕZo•þ~}„x¹Oͳî2`SL=ßó ¤ÕRé´n´ñpÎŽØ’e¦ù€Å�’èaÊ›º˜ÓåȺt©y;5U�¬9 XŠ­ûgž·V‘—‡9a÷(•U~ÝTu³�N¼Öüø�fx� v³{µSö.”±ô$:„Ç¿íl¿&÷.¬íÔ<ÆÛJ÷Ïë:"vngµ7Éþß”P·r¢KÉ SìmAó_ÆÝ×uÝ*€sõsÔB®03ÝÒ“k…QiÊ='62ºwþ§ç‰%7CŸ²ÝûG+J´¢ØJ‘ˢ诃~&²dÉ?GÑùX1˜vÙ#�Äž(Eo+¢-ll{T@"òyg¨…&ß™úðïó¥ûƒßiÝŽÀ¯×sf i>¦§üÆòŸ�\¿@¦¨oåüO74!hÔˆû,ÜQp ÑÃ&—â^šý£ªr¸{�µ”g1ñ$ˆ¼#ýUl‡|; Ü4x+}E°ãq× 5¬$4]&ÀatO¦â_†xå+¡û‘a¯¹3q Z›×ÝN¤IùòaÄ{í:ûrX°L\"Í—‡poà°™ ¬Å úu ‘­ª^5�äâY_§âïísŠC$j“+ù‚0GRä—¶¢ûוU.[MdÈ@ÂQÒ» OÌy°q¨×Ó}KÔëJ¢kxu~y$É8õ)lSì[D;›W¶ aãº�Nl/.©Þôw^]ª9”R‚íÁ�9¢¤°Ý-ܼ"“.½åOó D›ôñ‡lÀ.­ˆX½5–œ+lZØ·Ë#¨¬óïvÝOºÌR¾R…™p£C© H�k�†Eðßþуv­M‚†WÙŽ^'‹“Œæv¡�(W³Bô÷3uÍײÆÚ/&‚T[üÀ"—OXÐÀǯÑÅ‚-�¬-ݲüò€1�c‰åáJÙÙ8±Hêµ ˜'jŽyÓ-]=h\,o½ èr"´7xµZtnS®|cÅ÷ ‹™ÌÜøFkÄ0T­á0Ú~á¼8ãm-ý�a¡Ø™üÙoÃåÎ4T•rs�ûýO‹H¥šj[³m;3XæPD„ÇQ"FT(Îâ¶Kç€Ø8 µ.‚ƒ™—…®æº“Vu¼¤$âÈë%ÕõRü®=)eÇÛròÔÍ¢�“ôžÏø%™<™�»VÇR9ñ‹ÑUº(ø­î!9‰�‡Ü¥@+¼'Ótû‹]‹–&¸„L‡©œC$�Q´Àÿª4Üàñ821°qùøŸ Ë·#³  r/¨œ»SQœñ •é£>óØ@%(: lÛqW™�úöÇôJ· ¹=&M@ ¼®=ZE;ð§xT/l îfªž/ÌÒœ¬Fq—¤ùg)=Qô*j2É‹2ï·O�ãJäE<îXìSŒ‚àÙïê›Þ¼39S5töÜ""Qµ¢Ex^#pŠ8¸˜ÆÁÄþ�‘ö"6ÓdGx"ø6Ì:5ÆSŒÜ‚óáR/e„�²šùnq?övÍ™¥£C{NQç× Ùå0_—ñ¤u¶œŸL;ŸEtéþJ0BmÍ‹�öew#¿b­=4í"º4> J|�aÙ­cëe+Ú«¾ƒX—L*ùŒ^{–Sèò춦™0‚ Á *†H†÷  ‚ ²‚ ®0‚ ª0‚ ¦ *†H†÷   ‚ n0‚ j0 *†H†÷  0P ¨ùt]ô‚ HæÛÕfY6…óˆþÊ8sÅö¯…yÄÕ¨�O9Á -Ô-�ò_—ºPªød{r¿G¡Ž�G‰0;Ùï&þöU´HEXkÁO׸ø#’¶þÒÓªœ¹L¹¼Šq[ѼsO1ªº­3Õ=+3¤輨¼ò’°Õ—½¡ÏýÕ—è¦qêCȺ×{êÕjjo¬ØûŠHWr ä‘õ�OY©çS 7A®“-�aûç8Y™¡ªÖgb+„ˆÎûߌ麪ç6Ó—å ˜…ýÁ>áž8;!³|Ô?ƒbóÁ‹VqúS”àaR­îŒØ…’@•NÈê€ìØ×öä¾Sòx‘(¿�“&‹ƒWqÞAJ°]×·öëì‰ Ž�Ò§¬3ATõX‹ø+̼õó¢)w&,^ýŒy½z¶Ä›ã 0@å‰KOŸ äo½…¾ã ñœuQà¯JÍ ÍL¨¸-½á‚…!&.ò†ö•Ó<§ÑÕ,sH¼£ËW’¨gJrêÄNýÝǸ–T`£?tnßS¿VÊ—vkŸ*5]8Þ]·j5C,ÆõEüas‚ë‹ûöÒ÷M‡Ð3ãÎ9ú4$ ã¸d!9TÊžÚäD8Èkº0ÐCv‚°Ð“B¿ Ó ‚È}Ę�0lN¾ÅžùW= «w˜‡o û5+4XxÃÜ{"5–n EËsN. Ò“3� $_Î-W¿`ÐjàtUmëŽMo�ª'å§,–f~Š4y‡ß½ o¾)γBc /*pÒy®µf<@¾PÔ˜Í KÃh·Æ¡@w²�Ú}™ØºNËÅï7P÷SQÜÏk<`Xˆ"²O4¹<�9`,DÕˇäTqN|Z`fYŽ�Ä*¤ºpaÁY"uõ‡&Ð-ZÔÇö]#V×…½Ü-Îs§‘„hÓÕ"L8µ]g´üéé_@ÕcEñuµ�Nb‰U÷š˜QõOœœ}vWEÕvɸ‹a¹M5’QYÂ^¡HË.J= lhœ§N9û~!PÄtù‰šÎš‰®»X\ ý«VÜ2CL7™™pø;&+jþî1p–;¢p£Ê8í~|S,N¯Å¬‘WeE��z)wŸM"E*°ùJõ’ÙN–¤uù¦#‘û”Í­I?ýI„D[@9]ã•AIP¦1Fβî7f^åŸùÆÝ‚æ”A�ž•»»É²É Àw.AÎÖ–Z¥ÏAUETÄtc)€Ác‰Õ‚?®Š¶ÌÜæyÓ¶0©SLéo‚­¨ê]î)בˆ¡uTh£6ãí÷°. §6Ö:ˆ°$GöãËFÀ¶k3 „9CÔ OV¹ÃÙ(ÉÇêæ“ôø'Û10±"íà:ë]T|“ËuÂç–\1 LlfoxùKÒ. ìP/3n ?Ù2\‹~y_ mr–z×N((ãaxej?‰Ís6EØ3™˜—iêU,ÖRíAD‚ÇJV~…6»×¬cÍZóDÀ ˆUç`y}mÆÑÚ$ dŽp½�ë@™.¯]–z…�ÈE¥þv¾A”$þ c+Y± A'iC¡‰#Åóõ©ñ¸üYž—M´mU]ïÇÉ)éÙ˜¼_¢‘ÛúÆŒø¢õï¨ø�qOȪ†n˜ó vù6/Ž ¨¢heëKÜ»z\è #•Nš.FvE”hóŽ8î|¦&NðA¨{çEÞÂEâcÏÂmùÌ•Ÿð%q‚bMOô*°ŸíÛ˜>QW²úÐìV–Ãâšî€uÖ¸ãi|ž+M’”²…Ö4֤ˑ(Y‚¤I±1K�BR Å£v~cÇP-Ô ¾U ]8ù›$°õw«ß¥»Ö1\ñ.�ÖÚéÁ2À³Ù_F!NЖ¸“ &¯iëBž„›=Ëb\˿ݙÅÈŸ}s| ›/Ç ØöBtчžæ»`Õcma¬ˆ‹%§Õ4{ÜmÛý…ϦÖã‚)�ÆìqŽ÷�CY£ò_—Áµ~†Šze×6íjãk?õÁßkõÑ@ÊØ\uŒÂ !4c;4Zĸù·Q9õ`æ *sã*@þéreEûÎâ2]f l+M7 2Žçêd�d•sa¤q×Þág/V¦Hƒ ÿ¿e3ÌšziG¶ÅÜB!†ƒ=ª ‘87ŸõIÑI�Ç\ã½�\Sðd"Î^Ó¿„9M“(*g0e±&Z�öiU›“Ó’d§ºÖ`€,b«-Édu{“ÙEŽ<›�ƒÝ+ÛBæó&­2§üW÷‡ø°�:üù)¡öÆ£Ÿ¡`1#�˜ !ç}›¹Üs‡Ê­-¾`¨Ü1¤×T?­ãÉÍ=é6«aáŸÁæò=^úÕÐ4Hpc6�Òà ô·Lâå%kA�!.Ò©á61¯²T®„ÔPhQý8× Éô'šù&gÙåí½Wa°784Y Ÿ@Ó:·Ïð__û¢ªë™¹¬ÚÔ\QFÅ}^LÒ‘ÒÆà5)–ñÈÍ$)˜$±·ô[Ù¤Ì@ ·Óý Ò{ÚˆÂçïÉÚUˆ9Üïî‹ÏÏð¹?=ÊDäçþð۵ؚšT.ß";cvªxÖ¼…‚¶w]2’†½ .Éän€©cÄ‚½`Ý‚§¦(Kú + EÉ}j}8ü>ìô4‹8¦ÏãVn3ˆWW4ð¨L§ TrUEܰ™àaü¸ÀÐ�� Ús6’TÔ·ž£,YÅÜA¤µ±o‹¼H$»cµ-­Ô úõë1’ú~'7A$Ư•“aúÛf¤§èÊ®�¶g(–xü”'Ãk#ö{F¢š@C¹<¢mÖXéeY¼µ]xÉ—ßøÔ ¿nضô‰(Çm´0Ãí¸³d³FuÐÃ¥?àœŽDVVªXç·” �60ò¼\»å\²� ðµ?µw—"Êrg‡6‘Uõ¢hQ•’¯\À“ïRÍ+,RBóÛÝ.í­+ëÄ�V:¬ŸsIõ©˜~¼ê¨¯®_O"Õ¶b èùõ•xòùdxè¦ï¤N@áÖv-F†�©tÈü•ŒtBú7Uçu%²ÔMG?ÜHY‡I×*û¬òÇfä‹¡ûÊ`ÉÛ$ÄêR1%0# *†H†÷  1÷ñ¾®A¡a¼’Ÿ(ù7_^ËÆ>010!0 +¤âTÜJ/>bÆ+¢÷¦à"°Â_Òi@È%iHYOpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs/localhost.pem000066400000000000000000000035531527232126200334700ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIFTjCCAzagAwIBAgIBAjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBw ZXQgQ0E6IGxvY2FsaG9zdDAeFw0yNjA5MzAyMzE3MzNaFw0zNjA5MjcyMzE3MzNa MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC AgoCggIBALzn4xcbGhSX65fgSIo+NB4EOYX+zJxbHamv+hbQkhAxqHxUSszDD86+ s9ZsN8cvpDIRex1/SfkNRKhgVUHGiUYbol+9RLpgpdHYLJCY0S0kOyBUgWqEcQrA tVDYpwaNC5qMneiZkcNvQ74pnuFOa0/bzbpLyOjYKEQq3BXK32yGLLHseb/PIX1o bqcuYiR6yI7S3wK9hJzSo6BRPSz0cNZNpnXbW/yLRtHbthBtzTifM2MW2jtWuFvg OW1ly9vxwTHCrJv5KxMubVDrqAx+RmmOsn327APO3r6NUr2CzV1vG8CMqLApse6m dKpCZ5UNLm4dwCUe2zWAQ0Q2Eba88O480bH8k/t8NUGXlWt25B8BUE8rklY0jwSw v8Dyjda0moeoxgMMZb+ogPjTY/Ds/h2hgFzy/DUuGrv6kyVxzH0/pOg29HeDoUaK IaqjAsN8h/oYTJ6CiOKAqWfbi8JZRmiEVTekskS5eySsPqPCegfAkfpIlz4EU4FN 0A2vORI7epW4mNiJcCLb09v5jogK+DhfeSscDsrYgIF8eAPLw6r9h1am+vXoD6vt tIwZBu15pnCWXdDcKWBNjx+zYU648iZ9V/qFG31uTJaw0z18eFPyTcJN8StTnoGZ zjKI2AyjG5F6ov/S7mnU3I/wv0B5Vq6fPjSvMrsBlbBdI3Pbr3w/AgMBAAGjgZ8w gZwwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCBaAwIAYDVR0lAQH/BBYwFAYI KwYBBQUHAwEGCCsGAQUFBwMCMBoGA1UdEQQTMBGCCWxvY2FsaG9zdIcEfwAAATAd BgNVHQ4EFgQUz9tP/qEPtakX60jnqR5QFli0ODwwHwYDVR0jBBgwFoAUWctw9L0B ogbt5p4IKvI4hGREaF8wDQYJKoZIhvcNAQELBQADggIBAAlvZPF7W+Y7kN95SoBp oZNxbKGHBVV1aZu62XG3h6HTuTR/Wv1WrATEjvOZ/mc6PGWAfry65B8U7ra9H59l rWxV51ubof+L6Rm4/c/yibPmqEfetT3MfjnVsegb6bEF4AK4729pKAt1PB9T2Ck2 DtjNwHTKlMravabm3mjIV+KO8K5hJfVtlkdMBBdJ+Ydtp2mL6xM5AJ3xXZu7rqAL UiB4Y7yks6L68QDKsudk0Ek+yg7waCE9btSZi8f8WfXfGLYgDf4gA4fnwr6sRCRu wlOKrewXf19rppum44huO2q9FgEMuTmmTFH37gYBumN+NRWj7Z4ZVfSIezIAqbht 08PO3ksNKetg2eXE8umGoMXNhwd93hYD2QAkrzCzPUFIm/fY2uzX4I9BEnpJXWpV sSVs9MibckpvluawpF0IVBJbZouIBwsZxdD+LWTLppK0IyYRtpm/5YkswY5CtWvw HulHc400xmtzYN2TfDOKE/m+BEE7wr+ALx94hFr/FIRGMS6I2mv7nOUJuaYtCwsF t7WQYeXa34YNThAMIer6v9M3XNg8YcSeQIC+UJExzZckPNKt6xYJJwrZmu6AYHMt XYLfKKaCXABXHorDMjHYf0KPsw7e50liAlxkL+y0CkVCJEEgk6e8N0frTcXfLiZw FcSlZjHxGjwwIYgfDsuuT0jr -----END CERTIFICATE----- master-with-all-cas.pem000066400000000000000000000077451527232126200352060ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs-----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MSQwIgYDVQQDExtJbnRl cm1lZGlhdGUgQ0EgKG1hc3Rlci1jYSkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhh bXBsZS5vcmcxGTAXBgNVBAoTEEV4YW1wbGUgT3JnLCBMTEMxGjAYBgNVBAsTEVNl cnZlciBPcGVyYXRpb25zMB4XDTE0MDQwODAxMjUzN1oXDTM0MDQwMzAxMjUzN1ow HjEcMBoGA1UEAwwTbWFzdGVyMS5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANtT0Se0OBG+bU3ZbZ2IxiSKNs7ZxDBoyXVeVGvOvEQW 56TkHnYdoJ3bn3zLctAoWMggv4DxO0nncmVJYbFoeZo9n7viUQdsO8+hTWVJCjov uZYNO88Q5NE4zP/Pi9IWigOzjNMl959ItGI0Sr/aPZUpsc/V6eEpyY0eREGG6Ixa eeO2z/kU4mqO9CK4VzNxfZQqAi0kJEEp2gQ8Ax0gCXee4gbBF7zvyi6467Q3hJTf 413cL0jMIPHbNiyXdLlzjtmkYDL9mjnXbL1W339twBgPzs/ZjDqR4IBK4Fzqakoz WvWbp1aTYkRqSBiNRHtiQleCXG7JU6FDeF/wzXXWkWECAwEAAaOB2TCB1jBbBgNV HSMEVDBSoU2kSzBJMRAwDgYDVQQDDAdSb290IENBMRowGAYDVQQLDBFTZXJ2ZXIg T3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBsZSBPcmcsIExMQ4IBAjAMBgNVHRMB Af8EAjAAMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwPQYDVR0RBDYwNIITbWFzdGVyMS5leGFtcGxlLm9yZ4IHbWFzdGVyMYIGcHVw cGV0ggxwdXBwZXRtYXN0ZXIwDQYJKoZIhvcNAQEFBQADggEBAFUas+1NvtqTsT8X CHiwL/njj7at7V6BsF5yw/MnJ2oEwkJpfsp7J3aB/R1s5bxjtxOJ5fVzED3L0uIf we29p16rdSeINn9D/LShF7SUFIB3GokT/L5gHgYPLGH4itmz+GKul6qBdt0bOydM 1CqfKTmMEvH0sicEDRFIxji+dfrS6lPhdDHkdKGJeEWpNuATYmw24NYOIpO+4Bv7 oVXn5hoZp5VzbokCzVha1hlsUeG+wp3GnOoN2aaAm3LZNqKLhm5dKoNeRtECFEOu +GViwgc9RG4GN4jNDGU03+z+SMozlt3cc+osIxeOKExiK2dfhJwA9Uj1uvYYnSuy /hHeAt4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3zCCAsegAwIBAgIBAjANBgkqhkiG9w0BAQUFADBJMRAwDgYDVQQDDAdSb290 IENBMRowGAYDVQQLDBFTZXJ2ZXIgT3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBs ZSBPcmcsIExMQzAeFw0xNDA0MDgwMTI1MzdaFw0zNDA0MDMwMTI1MzdaMH4xJDAi BgNVBAMTG0ludGVybWVkaWF0ZSBDQSAobWFzdGVyLWNhKTEfMB0GCSqGSIb3DQEJ ARYQdGVzdEBleGFtcGxlLm9yZzEZMBcGA1UEChMQRXhhbXBsZSBPcmcsIExMQzEa MBgGA1UECxMRU2VydmVyIE9wZXJhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTgKLGBkExFRXrQJn/lHE4XHkN2nXwJpS+y8bWqHiBdq5eZ8D2 UAILOBaALeQN/1d1J4yrh6w/YK+gRtCLn+CslR+9NW4AgShALi+r26DK9ZRk4F7V Dk4yEjNpmTyVRyP8w7iZwasZdyK04xAhj+yEInz29SLxmh1jddts/rjqLMZW/s0S T+E9XSEDYNVprC5VuYutUuHKah7AYSp07FHNsqDg+y+vCRezSqbrHrGpTwMupVmD 2ObsSJntghsLzPwjSGhbo6e8C/TDwrPtm6az9TPKbsUrqjdvyZcSfc5Q6OgExNhg zWQkk5PqFOESsQSBfOOn2eqfqBXHUnH9PCNTAgMBAAGjgZwwgZkweQYDVR0jBHIw cIAUFq+AJeP66ki/kTNmAf1R7yRnTGOhTaRLMEkxEDAOBgNVBAMMB1Jvb3QgQ0Ex GjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQKDBBFeGFtcGxlIE9y ZywgTExDggkAsbkEcvsRJ+MwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAC4keJ+jeGh7/EWwsCKollYW7H4aSjPu/Ufe38hH pEER9FyCqJ0jo+MabOx8l1F5ySNWngB0qbJuA/kiV2gJ1bQ+mE2TN88x6Sz12eol ifhFU0PazGdpNQRhpQxbwJ7tFC3Z8WrHEcVqP9iicNWqSI/QkqXsCk4Zyezpx28W sqHylf1CiBOU45FJdDXRg80mk6WOpNZR8HIUdqQLQDXz0FfXeFKmVteatmc/yrGG 5iHzMkH4Vz5laBjin9s1p+O8Z7+cWtJNWfXaULAEecZQ6CZ3V1OVOjhsrL28iF7C kx01rSrsxaFclDalJVmKmO2spHvNmQTlWD6jm5d94WaRyXU= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZTCCAk2gAwIBAgIJALG5BHL7ESfjMA0GCSqGSIb3DQEBBQUAMEkxEDAOBgNV BAMMB1Jvb3QgQ0ExGjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQK DBBFeGFtcGxlIE9yZywgTExDMB4XDTE0MDQwODAxMjUzNloXDTM0MDQwMzAxMjUz NlowSTEQMA4GA1UEAwwHUm9vdCBDQTEaMBgGA1UECwwRU2VydmVyIE9wZXJhdGlv bnMxGTAXBgNVBAoMEEV4YW1wbGUgT3JnLCBMTEMwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDFDXbR+00AwXM+HuMIpw8eVWBzQWBqDCYkX3IvYRGj+w9y 7AitrN+J0MZE3pbaRvlH5wU7MShFOmT0k/B/wrylW4W5G/iAtd2ZnXicBPrA9zDU eHJftQxR7+Qjmsc1BqVf43PUlQITpn1APgXDzPJdk9XbRWEsIycuXkwTXzVND0U5 z3dGS/oh9yMim0DnF2oQ+gTFA9n17xOD5hBN80U3fn4DXtcFGbtXOj6zBHsxgLCi leif2AB1oAaZ0lqkwk6Se0rFd3zafYLDAwCPCWlZSfkQ0C/W7WYx07PDRxSYs1H6 Viz2uHwqzyD6elxvJBGcrLdvDqTLL+w0ag3yMPWbAgMBAAGjUDBOMB0GA1UdDgQW BBQWr4Al4/rqSL+RM2YB/VHvJGdMYzAfBgNVHSMEGDAWgBQWr4Al4/rqSL+RM2YB /VHvJGdMYzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC/sFnu1TIr L6HhTft5aUaeLuO/329cDUHxlUppGRYrctkZvYK4b8TBi2BD+tcwRKS1kh4nrQhr xaBO+oUmyJeNwEPk40trzusV9N9tfqw8drBBXEVZGxrYRYovq/RqLfUQ224EF3z0 r74dAWL0R80PvVzeJfUsUw0KYgskfLzP5QSW1rrJnutfYP95EMV4yWyrNqnDko3M v7XENh0TMEolMxPZ+X3TqT6Q0j4aM8njswObyeABslt+nC6nLfgBvgDaSvEULPL6 u5aWNxp9WudGqGBvHoR6OXdZDRCzWSz52jnvXiZE4E0VnqsWxCmjDGECke4TRoMU rtMLavKgCsIe -----END CERTIFICATE----- master-with-intermediate-ca.pem000066400000000000000000000054171527232126200367170ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs-----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MSQwIgYDVQQDExtJbnRl cm1lZGlhdGUgQ0EgKG1hc3Rlci1jYSkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhh bXBsZS5vcmcxGTAXBgNVBAoTEEV4YW1wbGUgT3JnLCBMTEMxGjAYBgNVBAsTEVNl cnZlciBPcGVyYXRpb25zMB4XDTE0MDQwODAxMjUzN1oXDTM0MDQwMzAxMjUzN1ow HjEcMBoGA1UEAwwTbWFzdGVyMS5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANtT0Se0OBG+bU3ZbZ2IxiSKNs7ZxDBoyXVeVGvOvEQW 56TkHnYdoJ3bn3zLctAoWMggv4DxO0nncmVJYbFoeZo9n7viUQdsO8+hTWVJCjov uZYNO88Q5NE4zP/Pi9IWigOzjNMl959ItGI0Sr/aPZUpsc/V6eEpyY0eREGG6Ixa eeO2z/kU4mqO9CK4VzNxfZQqAi0kJEEp2gQ8Ax0gCXee4gbBF7zvyi6467Q3hJTf 413cL0jMIPHbNiyXdLlzjtmkYDL9mjnXbL1W339twBgPzs/ZjDqR4IBK4Fzqakoz WvWbp1aTYkRqSBiNRHtiQleCXG7JU6FDeF/wzXXWkWECAwEAAaOB2TCB1jBbBgNV HSMEVDBSoU2kSzBJMRAwDgYDVQQDDAdSb290IENBMRowGAYDVQQLDBFTZXJ2ZXIg T3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBsZSBPcmcsIExMQ4IBAjAMBgNVHRMB Af8EAjAAMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwPQYDVR0RBDYwNIITbWFzdGVyMS5leGFtcGxlLm9yZ4IHbWFzdGVyMYIGcHVw cGV0ggxwdXBwZXRtYXN0ZXIwDQYJKoZIhvcNAQEFBQADggEBAFUas+1NvtqTsT8X CHiwL/njj7at7V6BsF5yw/MnJ2oEwkJpfsp7J3aB/R1s5bxjtxOJ5fVzED3L0uIf we29p16rdSeINn9D/LShF7SUFIB3GokT/L5gHgYPLGH4itmz+GKul6qBdt0bOydM 1CqfKTmMEvH0sicEDRFIxji+dfrS6lPhdDHkdKGJeEWpNuATYmw24NYOIpO+4Bv7 oVXn5hoZp5VzbokCzVha1hlsUeG+wp3GnOoN2aaAm3LZNqKLhm5dKoNeRtECFEOu +GViwgc9RG4GN4jNDGU03+z+SMozlt3cc+osIxeOKExiK2dfhJwA9Uj1uvYYnSuy /hHeAt4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIID3zCCAsegAwIBAgIBAjANBgkqhkiG9w0BAQUFADBJMRAwDgYDVQQDDAdSb290 IENBMRowGAYDVQQLDBFTZXJ2ZXIgT3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBs ZSBPcmcsIExMQzAeFw0xNDA0MDgwMTI1MzdaFw0zNDA0MDMwMTI1MzdaMH4xJDAi BgNVBAMTG0ludGVybWVkaWF0ZSBDQSAobWFzdGVyLWNhKTEfMB0GCSqGSIb3DQEJ ARYQdGVzdEBleGFtcGxlLm9yZzEZMBcGA1UEChMQRXhhbXBsZSBPcmcsIExMQzEa MBgGA1UECxMRU2VydmVyIE9wZXJhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IB DwAwggEKAoIBAQDTgKLGBkExFRXrQJn/lHE4XHkN2nXwJpS+y8bWqHiBdq5eZ8D2 UAILOBaALeQN/1d1J4yrh6w/YK+gRtCLn+CslR+9NW4AgShALi+r26DK9ZRk4F7V Dk4yEjNpmTyVRyP8w7iZwasZdyK04xAhj+yEInz29SLxmh1jddts/rjqLMZW/s0S T+E9XSEDYNVprC5VuYutUuHKah7AYSp07FHNsqDg+y+vCRezSqbrHrGpTwMupVmD 2ObsSJntghsLzPwjSGhbo6e8C/TDwrPtm6az9TPKbsUrqjdvyZcSfc5Q6OgExNhg zWQkk5PqFOESsQSBfOOn2eqfqBXHUnH9PCNTAgMBAAGjgZwwgZkweQYDVR0jBHIw cIAUFq+AJeP66ki/kTNmAf1R7yRnTGOhTaRLMEkxEDAOBgNVBAMMB1Jvb3QgQ0Ex GjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQKDBBFeGFtcGxlIE9y ZywgTExDggkAsbkEcvsRJ+MwDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYw DQYJKoZIhvcNAQEFBQADggEBAC4keJ+jeGh7/EWwsCKollYW7H4aSjPu/Ufe38hH pEER9FyCqJ0jo+MabOx8l1F5ySNWngB0qbJuA/kiV2gJ1bQ+mE2TN88x6Sz12eol ifhFU0PazGdpNQRhpQxbwJ7tFC3Z8WrHEcVqP9iicNWqSI/QkqXsCk4Zyezpx28W sqHylf1CiBOU45FJdDXRg80mk6WOpNZR8HIUdqQLQDXz0FfXeFKmVteatmc/yrGG 5iHzMkH4Vz5laBjin9s1p+O8Z7+cWtJNWfXaULAEecZQ6CZ3V1OVOjhsrL28iF7C kx01rSrsxaFclDalJVmKmO2spHvNmQTlWD6jm5d94WaRyXU= -----END CERTIFICATE----- master-with-root-ca.pem000066400000000000000000000051511527232126200352230ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs-----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MSQwIgYDVQQDExtJbnRl cm1lZGlhdGUgQ0EgKG1hc3Rlci1jYSkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhh bXBsZS5vcmcxGTAXBgNVBAoTEEV4YW1wbGUgT3JnLCBMTEMxGjAYBgNVBAsTEVNl cnZlciBPcGVyYXRpb25zMB4XDTE0MDQwODAxMjUzN1oXDTM0MDQwMzAxMjUzN1ow HjEcMBoGA1UEAwwTbWFzdGVyMS5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANtT0Se0OBG+bU3ZbZ2IxiSKNs7ZxDBoyXVeVGvOvEQW 56TkHnYdoJ3bn3zLctAoWMggv4DxO0nncmVJYbFoeZo9n7viUQdsO8+hTWVJCjov uZYNO88Q5NE4zP/Pi9IWigOzjNMl959ItGI0Sr/aPZUpsc/V6eEpyY0eREGG6Ixa eeO2z/kU4mqO9CK4VzNxfZQqAi0kJEEp2gQ8Ax0gCXee4gbBF7zvyi6467Q3hJTf 413cL0jMIPHbNiyXdLlzjtmkYDL9mjnXbL1W339twBgPzs/ZjDqR4IBK4Fzqakoz WvWbp1aTYkRqSBiNRHtiQleCXG7JU6FDeF/wzXXWkWECAwEAAaOB2TCB1jBbBgNV HSMEVDBSoU2kSzBJMRAwDgYDVQQDDAdSb290IENBMRowGAYDVQQLDBFTZXJ2ZXIg T3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBsZSBPcmcsIExMQ4IBAjAMBgNVHRMB Af8EAjAAMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwPQYDVR0RBDYwNIITbWFzdGVyMS5leGFtcGxlLm9yZ4IHbWFzdGVyMYIGcHVw cGV0ggxwdXBwZXRtYXN0ZXIwDQYJKoZIhvcNAQEFBQADggEBAFUas+1NvtqTsT8X CHiwL/njj7at7V6BsF5yw/MnJ2oEwkJpfsp7J3aB/R1s5bxjtxOJ5fVzED3L0uIf we29p16rdSeINn9D/LShF7SUFIB3GokT/L5gHgYPLGH4itmz+GKul6qBdt0bOydM 1CqfKTmMEvH0sicEDRFIxji+dfrS6lPhdDHkdKGJeEWpNuATYmw24NYOIpO+4Bv7 oVXn5hoZp5VzbokCzVha1hlsUeG+wp3GnOoN2aaAm3LZNqKLhm5dKoNeRtECFEOu +GViwgc9RG4GN4jNDGU03+z+SMozlt3cc+osIxeOKExiK2dfhJwA9Uj1uvYYnSuy /hHeAt4= -----END CERTIFICATE----- -----BEGIN CERTIFICATE----- MIIDZTCCAk2gAwIBAgIJALG5BHL7ESfjMA0GCSqGSIb3DQEBBQUAMEkxEDAOBgNV BAMMB1Jvb3QgQ0ExGjAYBgNVBAsMEVNlcnZlciBPcGVyYXRpb25zMRkwFwYDVQQK DBBFeGFtcGxlIE9yZywgTExDMB4XDTE0MDQwODAxMjUzNloXDTM0MDQwMzAxMjUz NlowSTEQMA4GA1UEAwwHUm9vdCBDQTEaMBgGA1UECwwRU2VydmVyIE9wZXJhdGlv bnMxGTAXBgNVBAoMEEV4YW1wbGUgT3JnLCBMTEMwggEiMA0GCSqGSIb3DQEBAQUA A4IBDwAwggEKAoIBAQDFDXbR+00AwXM+HuMIpw8eVWBzQWBqDCYkX3IvYRGj+w9y 7AitrN+J0MZE3pbaRvlH5wU7MShFOmT0k/B/wrylW4W5G/iAtd2ZnXicBPrA9zDU eHJftQxR7+Qjmsc1BqVf43PUlQITpn1APgXDzPJdk9XbRWEsIycuXkwTXzVND0U5 z3dGS/oh9yMim0DnF2oQ+gTFA9n17xOD5hBN80U3fn4DXtcFGbtXOj6zBHsxgLCi leif2AB1oAaZ0lqkwk6Se0rFd3zafYLDAwCPCWlZSfkQ0C/W7WYx07PDRxSYs1H6 Viz2uHwqzyD6elxvJBGcrLdvDqTLL+w0ag3yMPWbAgMBAAGjUDBOMB0GA1UdDgQW BBQWr4Al4/rqSL+RM2YB/VHvJGdMYzAfBgNVHSMEGDAWgBQWr4Al4/rqSL+RM2YB /VHvJGdMYzAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQC/sFnu1TIr L6HhTft5aUaeLuO/329cDUHxlUppGRYrctkZvYK4b8TBi2BD+tcwRKS1kh4nrQhr xaBO+oUmyJeNwEPk40trzusV9N9tfqw8drBBXEVZGxrYRYovq/RqLfUQ224EF3z0 r74dAWL0R80PvVzeJfUsUw0KYgskfLzP5QSW1rrJnutfYP95EMV4yWyrNqnDko3M v7XENh0TMEolMxPZ+X3TqT6Q0j4aM8njswObyeABslt+nC6nLfgBvgDaSvEULPL6 u5aWNxp9WudGqGBvHoR6OXdZDRCzWSz52jnvXiZE4E0VnqsWxCmjDGECke4TRoMU rtMLavKgCsIe -----END CERTIFICATE----- OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs/master.pem000066400000000000000000000026241527232126200327710ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIID8TCCAtmgAwIBAgIBATANBgkqhkiG9w0BAQUFADB+MSQwIgYDVQQDExtJbnRl cm1lZGlhdGUgQ0EgKG1hc3Rlci1jYSkxHzAdBgkqhkiG9w0BCQEWEHRlc3RAZXhh bXBsZS5vcmcxGTAXBgNVBAoTEEV4YW1wbGUgT3JnLCBMTEMxGjAYBgNVBAsTEVNl cnZlciBPcGVyYXRpb25zMB4XDTE0MDQwODAxMjUzN1oXDTM0MDQwMzAxMjUzN1ow HjEcMBoGA1UEAwwTbWFzdGVyMS5leGFtcGxlLm9yZzCCASIwDQYJKoZIhvcNAQEB BQADggEPADCCAQoCggEBANtT0Se0OBG+bU3ZbZ2IxiSKNs7ZxDBoyXVeVGvOvEQW 56TkHnYdoJ3bn3zLctAoWMggv4DxO0nncmVJYbFoeZo9n7viUQdsO8+hTWVJCjov uZYNO88Q5NE4zP/Pi9IWigOzjNMl959ItGI0Sr/aPZUpsc/V6eEpyY0eREGG6Ixa eeO2z/kU4mqO9CK4VzNxfZQqAi0kJEEp2gQ8Ax0gCXee4gbBF7zvyi6467Q3hJTf 413cL0jMIPHbNiyXdLlzjtmkYDL9mjnXbL1W339twBgPzs/ZjDqR4IBK4Fzqakoz WvWbp1aTYkRqSBiNRHtiQleCXG7JU6FDeF/wzXXWkWECAwEAAaOB2TCB1jBbBgNV HSMEVDBSoU2kSzBJMRAwDgYDVQQDDAdSb290IENBMRowGAYDVQQLDBFTZXJ2ZXIg T3BlcmF0aW9uczEZMBcGA1UECgwQRXhhbXBsZSBPcmcsIExMQ4IBAjAMBgNVHRMB Af8EAjAAMAsGA1UdDwQEAwIFoDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUH AwIwPQYDVR0RBDYwNIITbWFzdGVyMS5leGFtcGxlLm9yZ4IHbWFzdGVyMYIGcHVw cGV0ggxwdXBwZXRtYXN0ZXIwDQYJKoZIhvcNAQEFBQADggEBAFUas+1NvtqTsT8X CHiwL/njj7at7V6BsF5yw/MnJ2oEwkJpfsp7J3aB/R1s5bxjtxOJ5fVzED3L0uIf we29p16rdSeINn9D/LShF7SUFIB3GokT/L5gHgYPLGH4itmz+GKul6qBdt0bOydM 1CqfKTmMEvH0sicEDRFIxji+dfrS6lPhdDHkdKGJeEWpNuATYmw24NYOIpO+4Bv7 oVXn5hoZp5VzbokCzVha1hlsUeG+wp3GnOoN2aaAm3LZNqKLhm5dKoNeRtECFEOu +GViwgc9RG4GN4jNDGU03+z+SMozlt3cc+osIxeOKExiK2dfhJwA9Uj1uvYYnSuy /hHeAt4= -----END CERTIFICATE----- OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/certs/unauthorized.pem000066400000000000000000000017351527232126200342210ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIICrDCCAZSgAwIBAgIBBjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBw ZXQgQ0E6IGxvY2FsaG9zdDAeFw0xNDAyMDUxNzIzMjZaFw0xOTAyMDYxNzIzMjZa MBQxEjAQBgNVBAMMCWxvY2FsaG9zdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC AQoCggEBAJkwwMlLQPQ0XllNlnvpyvd5zcRwPYLaQGakQatnAkls3K7Lzwm8M1sO cHU2peLmXV1ec/vJF5sg0MPfzTukSryy8s5jXUh3wiXm91SgQCAwWqv/5vG6qTh6 lQRc77YCg2vpd+zGoUVNx+Xw4GrXFSpWef1T2cbtgzmOYybLdKsEMqLFWm7w6nKb XbNGJYbzKsp69gsXJbD2j1vdmPm+s01g5XmoWG1kaJw4TqKmcZzJ0E9CHtpzOnw9 bIHokhA4ToBEGgvYeyiNxaDwMN0EVneG++1dGf3PjUQT6c51cBN1MIAsHinEcpOB quc0fuP927c7pAL80G3vDix0v3p1v+MCAwEAATANBgkqhkiG9w0BAQsFAAOCAQEA XVMnaE2UR47MzmUl5aWRMPOrCibJA04lHsO2BKb6R59MTHD26WA+6ED7qLhleNq1 1cZJHdxXXSKhJu0NMjAui4TwjXY4afZc62CgyOEqcvYVXtgJu6KMog1Lf8IIeFqh 06TIaZHgSHrBeVvOz/4nUFgm1QeKbkp9tu5NvgjlNliH/RnGPT2KkiL2iXU6MAvh SGZMXJF8wzQfSRuSYGtxOunOx392yalH7L2nEQOf5MKN1qgFxT3W7UO4kULhE2cS /BOC68Se5s5PXIMtUeQatOpxvopRObS8tz+ibRyfn0kh30d5llHcWtu2Eo9Ngf0I XEH+t1wG6e/o0z29zKk2Vg== -----END CERTIFICATE----- OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/crls/000077500000000000000000000000001527232126200306125ustar00rootroot00000000000000crls_localhost-compromised_revoked.pem000066400000000000000000000017531527232126200403150ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/crls-----BEGIN X509 CRL----- MIICvTCBpgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBwZXQgQ0E6 IGxvY2FsaG9zdBcNMTkwNTI4MjIxNDQxWhcNMjkwNTI1MjIxNDU1WjAiMCACAQQX DTE5MDUyODIyMTMwOFowDDAKBgNVHRUEAwoBAaAvMC0wHwYDVR0jBBgwFoAUWctw 9L0Bogbt5p4IKvI4hGREaF8wCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggIB AH4DIZpuzouVifUEMCADSG28SKElAz3YGnocUMIp5zL+QX2/PePRb6f4gD2K+e0F DvxWytVQFsj2wk3obAU9qikzuKSaD7bjBXlL5kdFPQTgWN+K4bPzLHFayh8Xdh9X paE6oqjMcO21ehIR49bMPtu6Ir+xY66Jg7ahZ1MmasU/jzOIYptKe1dkzdPdVZ8q YEwlVHnQMBSvZfS23Cz7zxFpRZa9CTvynw3hDnQLlF5Y3KJ8lVO3wY6qNxU5GVh7 zUfCTI1aHZw7V7EiuGLryFhG8PlPIQac3dvECIW7eBZG1XWnvVYvefa1dhTr5uvp NTT2IIGwjoYtmj0Zhiorl7PkCpsIpAn8r8lKVR+L3CdggCzVL+dEVSfR1mYzMmwF O6vHJ353OEuLP90ujalUNYiuBcYRGvMk7UPpCtD10KcC8YZ9U/lT3liNGpESh4DH XpsoAA+jwZ+C+NXCVKw2DCaERLxCQ7LMorNTOQVubkowmhLpfRNde8r18sg4buCB ZLCc5HSSPveVRfCE7J5Uu3Sf0/i0iYTuV55pmlfP/nUDDpntMZBQkfnxInQTVGa7 g0P6Y3nwbqKMc3/t43OUYuvd123zy1ysW/UgtJqVKIlm8DZAxSkSk2SR0AJ3xDjh SPjEGCj2ureZ7LDD20Kdeod3GETomrSXNZN8KHCfJoJ/ -----END X509 CRL----- crls_localhost_revoked.pem000066400000000000000000000017531527232126200357760ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/crls-----BEGIN X509 CRL----- MIICvTCBpgIBATANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRQdXBwZXQgQ0E6 IGxvY2FsaG9zdBcNMTkwNTI4MjIwMjUyWhcNMjkwNTI1MjIwNDQwWjAiMCACAQIX DTE5MDUyODIyMDA0N1owDDAKBgNVHRUEAwoBAaAvMC0wHwYDVR0jBBgwFoAUWctw 9L0Bogbt5p4IKvI4hGREaF8wCgYDVR0UBAMCAQEwDQYJKoZIhvcNAQELBQADggIB AIv4PB0NhOQLqwvdIT3dGW/VNlMAEUinN3URFGRptNeVrv8tzDGAK3hxTmwwjWOR 0gPlDnYdYz1pgVg6X9kvUzkPS1YLDTOl+H35MWOpN3Lr8/GbtVKXphBHDyhoE5Sk JEUcAJZYyRAuZ09QBO4mnJ8C/lcMbkiX8JFfW6KPaVxltmjssfK5Hp/771GYnYLb F6t/vvW4kS3pWPe+Nh5JvOSMzaHLQnyrl8nkWSwMmDKP7GMtHS1pKR5I4IR6kIcc 66Ec0Xq/RdrN+oD35y83+EXDaCZSD6vovMUugxLXy8Ak8xA+OAcBCUF9MSnSq4u1 gwibkZZe1rxqaoBCriS2jWsOOuJ5KSRv/4m/wXIozwZSdV64oFdp4zF7nnl8exL4 TupIxhn2V5PzxrZyBd2/+KxVkB++BrtwzfWvPe484dK8ueIzTC/IDug5I+eiFKnr U0k4056UGtTnB8eHVj33gxCsnnpndezg96bgRtZp/P4K/szcsGPwk4tlcags94eb 51vvyp+Vf6H0vliq1IckhpN4+zIRHZL1EqodFqOmaR36TM3AYGKqkycsZdH1YvVW 2CYe2ZYWUtIcM+hzivpLeAy/MCp9mxhZFvSdqYlbiWKI++CgL6C4jIdxRU5KWYRC NtzmIio2OISeBYQEDkMiXjxlIe0lLjQIh9agw/sJ+3pf -----END X509 CRL----- crls_none_revoked.pem000066400000000000000000000016161527232126200347430ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/crls-----BEGIN X509 CRL----- MIICdzBhAgEBMA0GCSqGSIb3DQEBCwUAMB8xHTAbBgNVBAMMFFB1cHBldCBDQTog bG9jYWxob3N0Fw0xOTAyMjUxNTU4MTRaFw0yOTAyMjIxNTU4MTRaoA4wDDAKBgNV HRQEAwIBADANBgkqhkiG9w0BAQsFAAOCAgEAbpkRyii9rGX2Vl2xtcqhF2lLsO5v icyzD1jZiWrYoVla6mrx1BZjr/3+zX1kV38HRpw/6BXeNNlaF+zhDYb8KZxxStOA aacc7g2xmjJPsKLHNZh2HPFQjvhLszrmFmQHpxj7h7YL6NKoHaC3qVUnyxhOGSM1 Hp5qf7HOueUz3DQ4vDrkC4/EQk2qyPnx6XgeNoTteWMWYI58eH+5Zld8xeKB6gRu 5q2ElQ1VFrF4TCXDsAIhjmVCnuJmWBOdGaTyioGWEDPPN2B1F5vyDECZs0O4SzQd jWEZOmVZwC0PejUB0EtI6A5a24jFFIyV4g8xQfHpWsNX9HjC8lKM5QNb8yLcX6ko kNvgzUgC4KP8bDf3SSqdu+xaXpEtM4izCr/bMTBTYhfYwcwHI9DVy9XRm4kcAD5d IYIvbMLu/4qOgn2fTHqjAuVe5Tyz0ySvDGrA4GbPTpvJzl5EN2O5Qwrhs+ejNAke ycVMnI06Vs+fbZKz+OD2n9KIR6CSK5nIdsqXyZzVllP9RSCaDuidfZPGoJuTSnWV DQ2jWPsRaiHDQmRv7uB8Mm7/J9CVDGVIwqsL1+9AJ9Vicvs1U+YMcpX8RSgTYqTJ H99WSesl/1cOz2VGitpkcZVEvgyYUkGv+9TIqffY6frYektUcpQv7QcaasZuLMXG qrrPossrUne1qRg= -----END X509 CRL----- OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/keystore.bcfks000066400000000000000000000224121527232126200325270ustar00rootroot000000000000000‚%0‚$I0�” *†H†÷  0�†0d *†H†÷  0W@å�·6mrˆõ°0 :÷g"¸Õ+H¯/%oØmÅúZyyàÎW�jª:8Ø v¦'Oª½¢Ûßš²oð#â`ÙpÇ@ 0 *†H†÷  0 `†He/0 µž—ÙÛë“‚Ö“î‚#®\Ø'ΔõNÈk$×0¿ Ò…)ÓM«ï<ž´HDÇlgº¢¬ýO€¯¡Ý3ÕPjn&$ÅèýLÎ`-çÀ¡]ñsL¶v ]°."Ë™nñ®ƒw€Çý>;Œ“ÌhúúO‹—‰µŽeÈPv€!s3gé«–ŽNžâþ�ý"W>ŽÁĤ¶é èÏ ß +¤Óö|u{!—˜^¾õtt3êúœ¶”’x2±<¡÷»94ª¢ðáŸ: Â~[œ;"¼X^µº3uc®#NìœtºÚ™‘¦Nõ€M–ÿ8þ“‡JRqj«à’H Ê5?I[ì˜}ŠÿñWà‡ê£e ´–Éh–s?ÿ„•³éªÙèŽÂ5ê·&þƒ�Q‘ÙKÑÂÑšÊÎȳ1a@~w{mª‹ NFŠ-®!¢Ü yhoØNKÁàÒýǪ@û$��3c¿Ì!„'WlS Úe'ßÒvÊí Æ·ÔÖwrVÚƒG¬¢OŸÊkÆA³áPŒ¼.Í[R.d\/üS$HͱH%rX|Oë‹V†wMÝFÌùn2õá%#wá�ÖÖ{QlðûµmŒ<ÌèµHO¨ÇdàVTZ¢ß›¡z"9¦›ø¯ù.&Á�NðòWØÅÀó�>7±/)pž«ðÃÇÔM�oËíŸÝ餴ظ(£c ú¤ÃPí¿ñãsyc!_sÅ©ïÀÉCpnÐùò�ä;´7kntŒSt0&… BsÔ˜Èצ|ãÊÌàY‘q¨¶C~Ö×>.ð(Ë)œ‘#ÀDV2Ì2�FßB’†9^‘5íK`*˜¨ko ´ë%¦V6 ê–hܸù=&O7_°ô9ÒNS˜…<-7}ÿÚåÿ˜Kðf§Õñi GØÜÝìýß ±®×ÆCí½E�–WÅ™±�.LkV�ˆd~À¢Ø‘¯Fš«P;}ìßM3�»ƒ¢˜\d×nËÖP•Rö â€÷]I}¬ûeú멱¾vmºô4º„ö`¾{’c€]°Ï\Ü›i~óJ eqy=ÛFº²°ÖEëW#ºA�(b»mÒT¨Ž¥€7pÛœ™ÊÀT¥w„)p9xʼn›Ì9²ä%‹�IÜrªå;îÀ×g" ¥Q›9k¢öéµâÄÓ×9CaŒѶÝö€°ò2¿ô6…éÑ{]†ëÀÐû5áq`®!±�Ïa;Å¿¦ŠÏ\šA3O¸c<Ï«€È”Ù3¾³NÒ|Ê™`y!®jø� ßÅ|¼²d¸bÖ3…qÃîìÍÏbþèʈw÷BŒ-Ï A O.“Θ ÖxÍÐ!šsµ“þaYaRb�DóO!Z¬•:j?ýF”~BJy<¦í É{½WšE…ÙiÄ�¹a¦}ìøîRS†ž]zÙX§ hµo¡îp‹¤sˆÃ¥›ò Â6ð9Ö °nÄ·~=@º#‘_а�%ê¸Ú®Ì¢|�2Ù13©¥4žLsCn¸æ($Έ�šš•Š³NÌ…uoè²Ï`‚à/¦_²Ô% Ìôˆçù#KŸk¦Ûˆãv©ká^—»gÿ’‡xWoÐÝ@ §Ãð`ÆÞ½'w †‹�8&,ÌÒ_ÌZ³!Ua1§RI)é%kI¥ ƒË<§Ã&Aà"-ÊgÃ…™åûÙèEï¦ü»M&ÔEsÚkØÜÕ þt< Vì« Êéˆ]kà\ª¡‹wï ÿ¶Áªøñ—WˆОúFÎ3zQÜØVžh•^»Eíö8´êÎ2ß—‰T~MõÅf‘½ü `Ymú‡¥¦2ùÐ’kiL;¾.Ëš¨=SãðÚõa`FW¿„€nf>ŽQºvUû=*ÅÒ—¬/{ß_Æø×kÚ³wzzA¯ª #ר·7° K¹9þ•¸Š—“Eg¨=íW=ÛÜúU-Ž8ÐSå¥RFôBóãZêW»>¥ªì'§s—Á¯`± u–ïL2Ôe\Žt³Mƒé`»PâOá¢SÃÞ÷“¡”Dš ‡(ÅGÔü@×Ð�<EÅÑ _ V i¼˜Æ©R( 6:üܨÑ�yÜ­bœs‘©óvv%SeM4,gÑòÒ»+ø ~7“ËgÍ´Ç%�èsÇ´’(âþ§­CC$üw–Ì­i©{ v%(Õ¾ÂÓ)b Œ•aƽY6ì,[…©y¼S0• ÌAzây;cº·¥õ·nÛ^u:F¬¸)³Í°D I¸šbÀ�¢ÔÓ,vGÇO7öHp> [xê ! ,¢¹8›X¡#ŽÏÑ›JlôxÊr€�¡MlZÚÀËcùÖ—¾¿lyˆÁUÃTò‡hnbë!) ƒ˜mRÈhò¦å`„‰¾2аo€•ú5fxÝ „”Äí:ìxuŠ’:Ê!,1ïçÄÅ42n� hxtFmNb\s’¼ÝŸísý[zå šÕaëEMëî¾±`üÁ\ž�Tÿì…æPa^¶ÆêHÄ ÖÉrL_!)ëtß«è ‚ì™<ùyñ ugúô”HãœÂb‡µ�1¯ “±0Ì.ìÖœ�™öt°¿À Þ¸]VL¢ÿYb°O@Köý¬¨¤à¤ÂMTÅ‚A'm9Å·c�FÜ-½vršpØìçêFµôÜhšÂ©Ð"¶��ÿ“¯c B¿� @“u°M\¶Æl%a¿CEQO'�œ‚zŠ6·= 2=¢£‡à³~jåE�ý(âÖ,µÉjG±—Nõ–(¦£ªœ ±§ LM‹u�Ãì¡jü4*ºoø˜° Ó ùÿ9 ®ãGç�…lÿm?w¡\éŒ;+kcáÈíþ€�(½¢W ¹‚¹úØí>h÷Ï(Öy]Ž)¬ËoóâR§ñ”Ze=¡�6B®é·KqrO{^çßñÁâ6üA8+)M‰¤I“7•†¾º `ؤ›,4‡ìª›_¶‚gF½ ‡gÁîËz±wÀ»à­Y~ôI½?—rÓ­ö×FŒ œ/£Q·f]ÆÓ±rœÀe¡ÈˆÆ8ˆòû·ç#ç+(©Ãk*€ª+€ÄØcAs8ö& a3άX±p9BHÙ_™Ë�¾ùŸyoy‘íPxÿ­ÁšM ÍêDÆ:nŽK¼e8´È€¸ûKÓQY-·–peæ>}ܲØîts™�.ªt:�Áw š©ÖïJ…/p«‘9‘J¹-�ï5]¶c›]Ï©;Ë™�¬ôðe¢7²0 lhñP]_\ã«»™‡ÖÐèFv2›ñF=¼L’[õ\ožÓÕ|húò¯ ûãl�Ñ*±f¤±ÜË ƒ6‡‡Îp®»Ê‚ùšÑt& Û]©>ÙË#´‘ éÇûL”ìÎ!XÐYuC%Htá_èpkÏwÿ2)mÆó6 »o–ÉÊ„ˆc½ˆŠïè�ÎG´â½‰æy:®WfU>�Þüæïð|�”Ô‘© ÙCaiЧ³ÍXÝG<•`—¶Gr¾hôjsŒ35º  Y²ú†zéiœÙ3’Ñqá KôÆå=0÷†ÞGÿÔyþ°Ð m¨Kûkþ~È8•٤ÉL)Ò5SÊÕù]Áò´¥·' ó³rŽ€­|2ÍK¼}9@¢€¦’¤NœÌGBj7G�½¯´½0l{¶_ ¤äS é\�‚c[ýxí±Ð]‘ÂBìO…=þ :±WGÓ`œ½EuˆWcSÂ=Ó"îMär4ŒÛ«0š0Fˆ$] *T ã׊Єâf”¸snÎýØM|É>z2.ÞeQ¼/² ÅCôĨ›Ô+ËŸæ™êsR¿êbð Lþí‰�“A;¥ð0ZoN½°Ò¬"NݺnÎ¥ÅJÑÚêƒêõA±¦I~pÅQåûd_8ËÛõ/n÷Zƒn�é��œô1'fMy½KsëJÿ;ö=ÿ NvDœÛU7ÌHïÒÈqeIuФ&Zf7´þ{±¼C{ƒºú&7{\/€"±ˆ·X1¡uì²M®« Ë`„ vÉ{&¾�.Cø ´�÷Û¹9<Ç�p¶Þt'ÙÔ„ l—)ç¶à�¶(pê \]i¥m£�†vñjôsð8þÆÚ˜®*ªªï˜;-Õã6½½°\)Ôhá+¯~ÚËÃr;è_µ¿ôé”þ8l¬àT'†’O =bX|¤n±å¹�‹.„”B‘×b8Ú‡¬ŠšÒ}’Fßñ.�§&�i$ί<´ƒa·®bI�%94œ)ûŒ}'F�bh<Ï ÁOão”ÙÇÊ“>Õ: tpB:ïQÆ<·—Ÿ÷GëÖ&9�OÓüT7Ž?,Ö!Îq–±|¨)¸�T53R¨ Õ¾wŽu¹6d�§ÄšµÆ|ó3¹ÇÞšPè àušz¦[šo¯}d1X�2تÃkuz?Û:"qßÚüÕ™Ÿü4Çk/ÔÇéÄß3³¬Oî&Æ=’;\øÈ@§¾¥Ð%N}díx0ÊiZV×Ïäü�¬_¸jkxQñÂ\vÕ²Û‘�-òøR,3í/•î›:ûï”®(²H~£¤½å ±E3ù™2…Ð0g*üO�]q”Á·¿× ^U;ÃäÕûcË�¨JŽøÔ6î[Œ_í2.½ëÒ@=.×±nžc¶�ð77vÑ86Pµ«oCk¼Ñï„ò¢½Oââx<”ÂG3¤�å½5n†å«yG»ÄȪM\Cb°»òâªÝÝP£_\ç%LÖŒ†iÎýjÛ8CÙ¨W«ˆæ«å¦MÄŒÿ B˜bc¸Ç×ã�Òv®¨–0B{^ƒFƒwžy2G°iÌTÉ0ï+C.¿óPô€Á¯š]P›f‘±ÜÆLÁ)Γ¹Ü¦Ì�DuŸŽœµíÓ¼Ìc„ú±ãä•CZdÓÈRŸœoòþé.¤?…#áî cÚ¥©(}±®†‹u…¡´¡+²öÇ‚ÎiŸI¼x±øÌßjÒ\ÎA}àî!Ô�ò‘ Ž[q2iÆ£}æ¶t00f›Š‰`%ä[8áÕ MdÙÃÀ'äô¦õÆÎß#oM},;…œZ‰¾¡Øb×ÖFÄ_ ì,bScÑ×Å{Dc­“ºópÖ'Û7=õoY;ž-êämέ6¨%Oºùí<,ñ†ìqÝlÛkâæÝp*ÚzZ! 0ƒ…Xìxß-#r˜Ïĸ·õñ“ê�#éÔ®ŸD•º¸ø¬CÉ~€7ê"?Á¢S4¥ˆÓ´‚Ìá+&‹IçZMÙiUŽô?Ü—:Òl�LGÔ_ ÿ,Sþ2õ²Ê 2&̓ ™q>yîϤp0\•ªØÝó“ Þa3f@è|JH׌‚«/öÕ|Ûû\Òé¾pj²çSd×…ŽÉrËFˆ”„xú¨±®¶jvPVPÜ�w1°ÓuR»Z�—¿Wý=CUÅãþo¸€ÁùS¹š‰Á%S¦øJF 8WØo׋�™VhéÿA+ÜRZ“’Û±ð‚;¢S½Á„X™Ÿ­È9\$šñaC³’G�SÏv»ßþy.æJ=ôDóy/Ù÷‡[ŠFyÌ.r¸%––ªÕÕWEÿõo p#,"Ü‚X›øD ¹ªÕEÈÖ(ÛßN]>S‹˜ÍSé�r�•·Öj;9~ ±.�¸[ÓÖ$ Šä\µˆÈ‘0Ñ´µa‡e}CIóà)†À¤… ÷HpFKÆ2«ß}6ßÞúÔú9³ø4›ü¼Œü®17ü_`P¹?þî¬{íÊŠöµÍúd» ò¤Sê4<"=å/l36ñ(\â. •U=ô‚ž�Í3„g]i¬káeཛsàñ´•Õi@Ä *Ͷ FŠ¿ÍM3XOàê|ìP3ŽÏóhÅøuv~Ȧè,�¾Jd+tÚ+ÔίI `Ii]»l¼åëÜ.Ë/`f±¥ǑƎ¼h9Vh£Óå#x D¶·Ûšk­Ý¸?ŽˆƒÕ·£ž+ºûg,DЬv�va¹¼¾l©þœRòå©["QY:s(>|r1D6:±Y Y”Råß pVüûy }#”—Óžµ 9YéØBóPÝotÐ:®ô7Ž>Ð$½<`IÙÌ#òiá$€õÐQÁPÿ«Ö�„úß"´ƒ@ëÏ5x-$ylòx�µãÊîGšKß_4oY 6}Çy*L­ À¶H_>mMé[pˆÅþ*çH'ÀVÚÀÏžkÞÍww>šUjzK¹Ü(Ø\Eg)ü)Öµñ·; u¨��ÒE-ôkû¢ßrn¯ DÛ&¸ÍI?3Áßö½Šˆ3øŽ}WZi¶…p6øàM?äÔ‰G§ñGŸ»«Wç®ß5“œç}¢oÞng†F;E)„mËœ*�ÇYS=+� yyÿ ÛL�z=mÉPWE‡/ËÏç•l±fÒÜí:U¥Òr¦Ødµ±M\`}”×N忍'ÁSXR�ŽÙ.ø~ìU.¥­û岂UÏ8ÚÁÍÚPëÙ"¦M"­X ÄëyQ’PbY�†Hu/]|—DOKÿ»ø<?Wܸ@ä-“óšDÔ~ Io0G_ ƒ:dûpùƒÛG¹ÿ+è�%F¡Å�‘ßl�Ÿ(6Rª¡u½hŒ^!¤ëÂt’TnÐdîôÐÉ›H±…l‹‚ðFµg+è#Ã.å›ðsª¨@ͽõrÙÍ”à¢Ò�ß„õŒ_ÔÒÿ£ MošÏ"Q¨‹óu+)�ÂDM¯{@³œ®Quª½N| … »kžZ¸îšø#a-ƒžf˜+è8¼éÛ5°ÊÖÑ€ÝÐäôDAÌ�iÓ®3u~Ž‘ei6tÎ7 å§;w‘)¤U-ý™Bik¯ðÛÁW¯&o쳄²zÊ®ùKÙ•N‡û/”m˜‰žÌß{ÏQØ“Ð9¥¢%ÆÅn„£•æñÞ’0‰öP+EŸ¼î‰b8iÌUÃÝ×t®áÓq¸¾îå! † ³À4 Íöw'x$Vù�³†¤5¼fMªH9'Ee vkÀJë‘ý>Ý@hK¸ý”¶PðÕ^·X§×ý.l™§=NPX”E¾Wžf¼Ó%²ÖîoË—íOÂ6®‘åé1¢� Ý�‰{ÎK•–TO‰ìO®�MÈ£¦‚Ÿk_‹ØÛ÷âÀ:˜¢MtÜOç±õƒÔ`2¾‰B Âï¶\k†jöw˜½/‹ð;^´¢m9Áu hšwºÇoÌèLöIU¹q¤¬g®¨«;Þï%‰ˆF¨=ÀëàË ¶ wË»M ÒÆ‚u]JB™€~:XQ–‡ü?ƒüòŸÂ6¬V`ÛLJ@w®.L²+²<)S8Ëæ^D£o56¨; Ëú'¤£®õ“¤”ÇUùˆ è/)ôâ­xõå?‰×áUg·2 !PŽ^öî4©”ë!/’Wó‰`"hHÚUÜÜÑ´ÁÐ|Ã<fg¶Já;‚Ôi¾ÐÅ®°¿uJ,H>rg7¥á�½†6ÜѦk° ‘e]Ô“{˜}k̸?S¸­ß™ˆB滂 ��î™qñÎtG·ŠÃ óÖéˆ`–(Ñ–RL�¾t¶FH¯,¯w£tW§Xù”HVÉmc9=2>.WR&ßÊmðq²å>¿¯œ£'Çï"*ËtóM01² ð÷Þ1;©)ødEÔ¯˜2§f1Çþ€“”…”½¼½Ã:acÝŽlz¤•'u‰J„²¼p…ÛúTÛøåRX ¾`'ÍsMJ¦ëC…Më}Æ+Ø÷‚sHZQ§ßï¯=Ùlí0u{ÿöVG#úõž n4‘–‚óŽÅ×/Év$ƒÏ�“ ®õÝîtIÇÔ‹^2Eˬ#-.k�”÷8ñ˜=ÙœÎj?‹u*ûÆ "Óÿ’ïBX \µ(³E:yYäÛcEN«¦ÆvúáLúû�û´«NEËá#¤]?f[öhZkÜ'† |ã¡øøÅÛ¦yF X=‚#_Ú…[0ˆÁòˆÓ4›õOÞù:«éŒ.Ï{û‘›!}’m… bÄk“+öeA“óûãYN¾$Ïnij3ÑtúðFyN‡zèãžo—OÚ�»¨ØäúÖÉ�ÒÖ82Ô(\ ÍJš@–¯ü‚Û#XO HÀ‰¾jéÑt;º¨Áº€0š¹Úíä_ðöPjo¯à½'}Ú`ËsmÞÒÚmšzÊ0ÏËv4|GÔY\I”ˆnýËÞ 0Wá.½C¯´}ÁŒþg£É�G˜aº‰… IDNtÞAÞµêÚAã½OYã‡3úñ¶¾Œõ2½¿Cô˜¸H«øôŒk�ÿ‚2B.ôuŠ€–kYûGu •mvŸƒfàù,„ª#JXNQ_¥½5o›í  ÑEÕ#zÛJL‡ÔIµ°šópþÈy.`]y‹¸)ÙPr¸©MCx Ý9 Ç,*¼ëݘ]ÊèÐ}@�Wù Á <_ Ë~¸¶ m?ìóyÒÖ œâ[¶†<‰î²K”öaG´Ëùì¾ €¿e˜š%ÁBš6âY]1á{´^7Ó#ëÖÕ ¤øGÛ=œ©�œp¾ñ¼aˆ~I¥ÆT õj>è¹w h“µ†èÖ[워-icXx†Æ”ÙÕ´§F£ dÃ&ó:4‡±M£á“^q�*Í*‡€X�Ÿ×jùl±à"‘«ÒMvï|:w,¹Ã¢ß# ïü±|ò<¶N'AÚ¾øÀ’”bÊ?ö–èB@%…v’q¤0nk‘ä3àXñ%À\�i7*[ìC´íþû»Wb“V�ލHW$¼0Ñ1júÙ‰¸›c— *e” «ÎÂæ±°b&·05,ó}Ày>‘º�V0…EÊ i3ŒÕ ûÀšˆ†P‘~L:âU;,ftÞ¾Y¥W_bô~yÈRB*·E¢¦Dç/ù}™W­–ã§~¥ö13óTÓõõïî3 ©{3…bÊé\ªøß\áþ]¯ï´¬nl«‰ØzeÀ}lV›«çÑé^çŒö`T`x6Ç®ÓÀ‘,—�=®’öMÙùPX¬À(ƒó@ÒÒ˜,ÈT:sFŽõM>¥¡V~Ü Ù/:„(£LÙŒæ5F=¶®/êZÙ';ÙAütí�'•gÙDw.{­ã¸ùï Z+)ÐJ¯³)<=m jôHÏÚ_‚ ›ôaΤµ4á8£´ÓóKÎÇÀºìÃëœìè –N…Yìt¿ÐÝX Tfþh–¤ÑÊŠßŨ„âoì‘f4iLªaÓxÔ ÈÒsY´-`e_H˜gŒ{b”Yלät1üЙßÛg‹Î`m/™pÇ`Ù©'³?7>9ª…`%ÕÅzàhŸÀ¥þü©>ü)$ø£Œ¸Œºis³–Ê¼å› K;¬º« :ŸÒ»¶÷uï =ËEÚˆ¥G:pzð¢ž*…‹dùÝD(é™oº´{›#†_`&�¥”¥V@g�xº6ï ±z'�$îEUÒĈòvòfÆÑ‚Œ‹¦ ™s‰ B7ÃÉ·åv‘H©ÈšÁ»Íι½ÈZµ1aµd4M+�zWE¡Š �¥`3Ø¢À\6�u²ÑüÓ�Õú»Tb©œË_üOÄ‹�§¾í¦[cÚü+CP&@£J§¦}¤Éè yȱQ!°ÕúcPµû°mè&‚¹œk¡ÁW¡önˆÄdѨçÚçÏá¥z(r°Ánó×bl(ûþ´µÊ^fd€I€+áeøÛÏvŸÒƧÌpû`Pô&v$æZu`tÊ2Ø—áÌÐkE`¶/,œ^|Y1ó¯Lâ.Z²‚î$W6þX«}À“ó8N˜U¥å®ì_áûÍvþÚ,aF%‡ÑüÕp‡“UÇuKÉgPìé´ÌÅõÕVš…ˆkžõÞióÃJ•Œ6!u*Ø]߯D™”@:71ccÅ^—7þ";ý1‡¾j�§â2¿öM7…cöE¦-¦ã •_o 7<#unˆ¶5w5Ýõûœ¯¦l-u8•E�Iy§õK^MèM¿ºæ°UÃY}�lèF9‰�°&Õ±›;»¾-§Ç¥i&°ü8ô5Çn¸©²/bbY!“ŠyØg¡án�2ÓUê1æÊ¹wgú]M¼çh;m˜ãÕ¼f@7ÖP_Ó�ØR=Ø/÷Ê~s¸&\én@Ë �Á Ð׎%$ÿ‚›‹/lÌBKðÒâ´,°öÕ~? Å±Ñfj‹~=%ïe°J†—:?¼Êܪ�A[™Ÿ˜¼‚Pù:ĵ¢±­&å�¥ÙSßÏb~}Yê“ I}¿1oÀ×sýÞ¼:Kð ù~²§phH¤žWÀ‰èì’Cã¤/}ús\î;y u³ù‰sºXR×�fèBƒÖ“£Ô803ZˆÆÝáé`üáB¡iBõ¶‹�^}"¬žp"ax%K dÊPyz&ñ Rà¥! ™CnHNrÌ¿ 8ÊZ§oîÎ�gÝ ¾]‰ŠýÌ3:mÙãY–ýe=�b½„­ûF3]P? ‚Ö3§ñÝ£Ó ¦¾k"pWùïÀ–8Œ+!\—â.ÅM‘ì¬ãü©/eb|Ò|zéSÛ§™^µ�‡ÃÈ|Ôõ±¶3²Í=$ÿ<¤ìÖU¤¬Î³ŽÖ‰(>ò�„[¶ôê´ð ½rDŠZ‡åGƒg�J[¹RÝSEÁfu{[q¡ÆÄ˜¡¦l„Æ:�)‹®¾ÑÐúe¿ßÃ�©¡vÍ·%RzmèQî\(tq6ÿmjGW�æú¶‘y_d`t ü3�ͯsÿñýc9]‚º�?¶yÀ‰E_j¹h:®¸J5á –�‘’Mëâ³ 5Q¦ÖãzNSk¶ÄØkyê¦$ŒÊ“–e*l+’}̧ìÛÅï¶œ \žT»Œóô�À;f‚�Æ1møäŽÈ`þÇìq' Í,ïß3ú¡g—©k‚¹á1Má[kÇ4G½.^XvnÀ¥¢0�¶0 *†H†÷  0d *†H†÷  0W@Î&ùŠƒ°¼UKX7ä ãPb³—}ŸèNaîÕ…*³üŸ‰¿EÅ%1³„ayáa‚V÷Oïê·1ùîäúÒ%@@0 *†H†÷  @÷el·"õÉÚ_V)„ñgšx©�@4Ök"™š,�™ ºæð¤•1dæÚãT²i>g ‡LO•†’xçй*•G‘OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/keystore.jks000066400000000000000000000212341527232126200322270ustar00rootroot00000000000000þíþí1i%Þ‘ †0‚ ‚0 +*‚ n:•™änß<$k‰12Ìa¡±/tײ¨ ¹jÄ5¥k–ù`ž’añ/�¢�iÇeɯÒQ[ϤM}Kd íë;6óHqžŸA䇡®ö‘%[s�íü´´ôiŽ | û¦Z(?Äò»ÎÜ͵»ìRŸŠÊWHæV¼PÉjJõ§Gö—~"�ù]q�Cqu‚Š3ÓÄýž‹¿=Î󌔴ÉXixå �.¨ÒK4ú]8£`²%Ô–TKmäb¬t(û첉€N*Šâr¤/Iöƒ\3ÿÃÒ/A[ë1)®ßæ"öiáð‚n¦ì »À¹�2Q¹D3?nu÷Áx-éF<öæÒ€¢`�‡Æ¯W‹ò'Ú‹h¤Î{-KNfñTÖ±_ÿË žÇ#‰a¥ÌÔd4ª å÷Gú[m G‚ðɪÝ].d絈áç¸Òº6fo æô•å§lD%i< yR€s|ÖЄó�‹ZŽù¶2‰–ÁÍ�¶ða$¹Œ!ÖI< �ùÌ ˜I�À¡-á�‚o¼iÝÚd½'“•7”Ì >œQùËDiCmI•\ØöëêQ)ÐøŒiµ£’5:°„€JéU£¹ÌÚn•’0ì€ìÄ&¨P¿�HŠ;&Ž9× 3×Ǿ Ð  Pl7]=Dßû´Í÷/ì8¶ÖÓS–ƒ¸Z…oéo¾qúê¼$U†£nŸԈ^âƒj˘ׯ/kYø< §€ñ°eia9´+Yœ:.%aßèìc�¤§ÔCɇO¾HBíÙù¤ÍB×îð,�eVØ/'ÈûŠRN*ö¥)z[Û¬!È}2JFÓÜl\=†>Xhh÷ª›Ú…p}Úì ¯hÃoÃF©j çìÕi>ý¼k<3X–s)N9-�€iJ4ƒ²ºÕ£ö„Y,¦»ŠcÉ¡!U¦žt†Sÿ‘Rø>ÒÑzõ n�Z,=Z@‡³‡è<šÞ;|&~c#Kóýáçý|~oeŒ¸Øcb*Ëd}gçQH=Ïl`^¡„¡²pfGñ,™ñ©?±0q/KÍ ’•ªnÎ6-•ÕàµQÕ1öktfQ ´j0kŸÒR`M²‘QÅŒm1àÃU3)¥®­Ö›ŠY�¡*œŸé˃@ƒ(`žBdñ:$”o¹•ªüÒ“ÓÜãÍ]ýº˜&DwõŸf&&+sùÝOc² WD´äCWú†øÜWuV ú:ÞùßÁïá…ÿÅ?°hÒÄ·S¹AÐ3_BfvŸž:Fãÿm€„dâý ={Ä9ñIÈ¥èáWo¦1¿É¤ßè]ï5¼ÿ›E¯s}]:úÊJï“ò. Ä–†½ÓÎA¡§ðó¼ H�XR3£9 ÈBÃ/ŠcPXäË�Â,Jµ€Óý H?`§+ÙúðŽ’>Æ¿&™É8:øH$IôæMA¢»½ófÈÚ; •‘Ç–œÐ´²3SHØS�?Ë¢7#žû®!Ò_:ƒTõN\&הּ`zÁQ ž4Y “ Ú·˜Ë3®â”ñô~T‚�#¬�áÕ�„:<3ÑË—·F¦š5üª”DQ\uL¯ßwN]³€)ÃH`…cNAÓþ»dÆŽ)¸˜Ð †bØëKïÀ …"è�I¢Ìhe\ìÅñ‰Z±­O­ýÍ¡ûãÐÇÙ2ZÒÓyO¡D¡A¿i%„à.é0¥P²²·?0Ûèü_Ío@2íÙÄC`áS�ÊSê«èA��ê ‘“¦wä ";Çœ=K~]]ý,<ü„“‘(ŸD®+7ïp¢a¡ÃW–|ž°íIÖÓÏm|EÚ#A“Èçoþ·A‘ˆŠÅéUXÚˆ,–ùYiKÅü€YŒyæYU8Úþ™,†Xúf79´�Ð ~í�`… "�æn餧Ç4fâÛ0óI ®­#Œ‡Õs“Ômlñj¦J›Ù†¹ƒf¸t à¯èµðŒ›XÛį1ŽF…ñ‘ïz�9¿7ÑEO†w A¡ƒ²De˜‰Žlú䙯T¯y~ªÛ6WP 2Üsœ�{l¤l‰�WœY™øµÈ}ׯ#´ºÐÐùŠ„ßû¼ÄÚBükU]SKkºàvTóám(´5N<ß§Bh÷X>�Ý÷—�ã[{aHy,¸ÕaÔ°ðV˜ìeX†TL"ëq±+R› &>M—½Û™*†(#”!lfc€Â3¨¼á$àÇ,´—¢¡‹5ºø~»ZÚ°o§<¢ \ý½«MR§!9�õ_mÆ5ÿݬëZ]ú×V4˜V!"Ë:4Nsê&¤/©’¬Ó¸üÑއPQ•L±áÿÕN›`vžÚ>±:ÐŒ�òY®Ì-)ž¯Ó>²›®M"‰3q.í[:«ÐmèjÌC ?®•ù|…Ï% Uÿ·²Ÿµ§Â‡´CüOpÉþÜ;�æž �íÚ°Ž –øî5V›r Öʺt �f'Ô—ºR{ŠyD�ÝæK ûåìZ²<6鿱L…"õîÛ%Ç×&»ð $µ¯]œOßÉS#|÷×pªI Ý@}í¾ýc$nLcÖ#2ñuQPÖïØ£-¼Æ�?âZ½Œ¡’‰2¿ÖžfŽ×ŒW¬§ùÏБ;Ž5"¢vh¹}(–Aqé(ãå5W÷ Ø©øé«ô 2W4Ŷ͠GA<�ÅœQkdÌ<²uÖ°ÂîØŒT¹nÐ˨ԹžÙõ¤ÎŸ2»r`›´›C/¨ªâ’Bç·0V]O¬�£W+c”âtª5A+‚òïÁìž)(…&«ß*—=ãšÞðûÐîõR íD&¿;"‹9†ãzY µ>XM&@CKÉŠñ¹åO²³ÍmêmêiÆu=é.Ù£+ÙC4¥Ížþjê\Ÿc Ó÷QóJ�˜ô¦l’.£zÌUñ§Ûˆ×‘€�¨ìœ¯ƒ”R]n.ÕŸi‘'‰ƒõ#§�ßBÉnû^¤…âYRCÉ¢•9K´0‰èÒÍsc퀮£ÕÆqÛVÄ‹R†®€ú<ë­õ5�ñÛvU›ÌÓÎLùŠPös¹’yÀX.509«0‚§0‚�0  *†H†÷  010U Puppet CA: localhost0 190225151740Z 290222151740Z010U localhost0‚"0  *†H†÷ ‚0‚ ‚¼çã—ë—àHŠ>49…þÌœ[©¯úÐ’1¨|TJÌÃξ³Öl7Ç/¤2{Iù D¨`UAƉF¢_½Dº`¥ÑØ,�˜Ñ-$; T�j„q ÀµPا� šŒ�虑ÃoC¾)žáNkOÛͺKÈèØ(D*ÜÊßl†,±ìy¿Ï!}hn§.b$zÈŽÒß½„œÒ£ Q=,ôpÖM¦uÛ[ü‹FÑÛ¶mÍ8Ÿ3cÚ;V¸[à9meËÛñÁ1¬›ù+.mPë¨ ~Fi޲}öìÎÞ¾�R½‚Í]oÀŒ¨°)±î¦tªBg• .nÀ%Û5€CD6¶¼ðî<ѱü“û|5A—•kväPO+’V4�°¿Àò�Ö´š‡¨Æ e¿¨€øÓcðìþ¡€\òü5.»ú“%qÌ}?¤è6ôwƒ¡FŠ!ª£Ã|‡úLž‚ˆâ€©gÛ‹ÂYFh„U7¤²D¹{$¬>£ÂzÀ‘úH—>S�MÐ ¯9;z•¸˜Ø‰p"ÛÓÛùŽˆ ø8_y+ÊØ€�|xËêý‡V¦úõè«í´Œíy¦p–]ÐÜ)`M�³aN¸ò&}Wú…}nL–°Ó=|xSòMÂMñ+Sž�™Î2ˆØ £‘z¢ÿÒîiÔÜ�ð¿@yV®Ÿ>4¯2»•°]#sÛ¯|?0  *†H†÷  ‚%ùž½”¯Îw쇆Õ>4`Ú“)‰ñ¬¨ØÊˆJïÿk»Ùg`~¹Ê½Œ·­”qªÏRqƒZJ¿ûø¿Ù{í,ÆŠ[¸�|¶"¿l»mò¶»fÁkžBw}„õ,;TüÆ(gtÊD[¼!¦~×­—]=çû@¹ó9–�C“zŽ#Ceåþ“ÅRÎlè…T�äßjLX;`»šýø"@‰íÈËŽÕ7œ®6øbÔ�űh¨KÉíO¡ÿe±jf÷p›ÚÍÍ™kÕÑ/öÌ¥«µ\)NÚPðšFþÁ„àµ}@'6É‚ˆÔ—,†Po�-[å©ÿþ¨Ðé�8Üò¼z .7,ÇMž›½mU¸“kðíÓ€uÈQçLL^^¢U ·ŸûOÚ\ïV‰¯¹µ™ö'v-H2"´Ä=Í‹ ’“³Ñ&Q¬é¥K'kVŸËg¨G³=k;ê8y­h²»3q »|²àRÓøÁ9M¤5Z¥ñŸÓÎy¬Ÿc8_‘ ¡¢„Õ{®E�·¶ìlC1§ÃÉF\°Móßš:ô¤�SpªÄäålÝÈ/Ç„‚¬yÌqP ˜WPU › �Áü¾ÉÐéû-[öqç,O�ßgÁP�夆tIÍSL‚ÿLþ(Q¬èþñVúíÏÁñ°E¶€  ì1NʘX.509 0‚ 0‚ñ 0  *†H†÷  010U Puppet CA: localhost0 190225143534Z 290222143534Z010U Puppet CA: localhost0‚"0  *†H†÷ ‚0‚ ‚æö' Ÿ9“ªœP\Öêý0Ý™XY`©ÁÐ_›Æ ¢ø=ëskjìrƒêmñ¡‹�ÀñœädùÇS’�üðñ Ý¡Ù¹•…¬jê �ºb¸õa™80‡gäÛÃu¤Õ~é/­�–ÔµõJ°Ýøí|‡ *òšfÿ9@ÄüŽÿ¾� ¹(þ 0à Àù`éW}ýGÁ=VmÃûÊ7‰C™©%Ð[ÝÏ*é‰÷ðÒá¬ìPÄu'@ë¼–}úo« í€@Gé׸³Ö¬#2dóòÛ%™Žyͤ–Ésj�¼î�FêJã§dãCÿMöJ¤\Jû¿mCØçöHt(¯4^öUÎÀíÁ`K¾,©’Ðç�ªê 2µk/n€“›€�^ŽÉi�BŸ–Omõ|Gy.Q¨÷Ãæ9"ÖWg³S�¤;wlÈIé£ìÌde{|¶õ¥P•˜%*nqµx7S…]:‹Ýiæò ãðÀ£ht÷Jˆ§Ã:7_J‚� ºþܦ0~ÇÜaç­=‡ý³cWS…£ˆ{ír~”�ùðpim3’¨mK²j "3§qŠí‘·nÊ(œôB¾K4bÆvkßIJ3(˜Ì¸Z‚â¹vBëH|Kêy© ��™—/ I «¬€nH’š £P0N0UYËpô½¢íæž*ò8„dDh_0U#0€YËpô½¢íæž*ò8„dDh_0 U0ÿ0  *†H†÷  ‚1¥Éy3 b&(:ŽtæQEæx¦üFâ4ƒ(†Iñ‰Î5Ÿ˜Ö¬2Ø¢pÁ?À'éÖ e©Zf]úHŒ±òâJFÄ vz}TÞ¿ºA�@è;Lªô2áe‰Ãºà@iÇÊ«N,æ�…ŽË˜‘í›P5 ™ tç{zB,—H$Õ.Ç»9¯UØ®hn ÉkSTR�î sû¿½6E¥Fm쇨ªàYTlŠ›Edoþ¬{�Vø“ÉU ‘Èþ߀šó(œÅxA ©Q7�rÓ‡ÙÄ:ÈõJùzÝÿ�Õ�v�—f|YƒBW˜ Kj'ôûç�1f%À¸!DÌÇfâ™ÉÌ2OÆ¡vŽå`_;KcålZ8ÛýºÙ‡±¸w8%$%æÍfmÇŒÿ\þX¦¿vü¸HÒ©ñ`CÀv³ÝÄ—ãVµ7üs-Íκïâ†Q…{4…Äp ÷ª~Ùª-BËCG�1ß=ûë…k!ï_´¢@å"‘  ÌÈÎ÷íñNzú}Ò…‚lì¶k-5\P”æ?cú—ˆ2Çhø0¥í…@‰å‹ˆ¯”¡KQ4Çu,.Ã_°�»ÓÃ/÷#´k¿2Ö‚ß `н‰öQK¸ötç9çÕ�¦_G}„ƒw@ê ‘ðð°]¿ï»œ¹Õå¼É:L³Ãlocalhost-puppetdb?äá®· ‡0‚ ƒ0 +*‚ oŠ_,!åu’çìlâ¯û¯ìïÂéü�`àLˆÕw%Æhm«I#PÉ� 7†ï¦ó£¤!lÐ/<ïšÑw+¬.VÕ§Lp}�žˆ,<+&¶BHzIn·ƒ8Ç–Šñ|¦>8ª»øÇ”é§@³„)úvk«F8 '`SÒxôU}j½ôpo×—Q;bM5fÿ¶/0Ëÿ?„!'tš�&ƒ˜}Øÿ ¡mä•ahML9Ê}X4óO¡NùÎÛª ¡†iöö’ùÕR̹^£Ö…HÝ–_µù¤y¨»F;ˆäà´­ÃÎídØŒãlkÝ÷Á�±Þ «ú…ÌP`^ë~÷‰µó<•9xxºlÏzé+q3‰½Ð|ß°ÛC@uOnQî$=ÙšeQK3|EuÚ˜«½åW8ZÈ,N§õ³I+�p½)9¶÷Ä›z=„–­í�¹Õ˜iã•*‚€¶� emK¼oùÚ‡E-8¯ŠÜáïÊ¢?&òc�ÄÊ*”r£&9#Xäd‹‰Í G”õžõáÕ�7;Ϻ•H6Rä†Ö³ó4æ/€®zä§�œîÍ›Ãlл³ €:Ûf/ü�9¤=¤�ÊcEŽôÑ}h'€ ¨ÄyØÒ Å*�ý½ëÙ6= óm˳@ë…Ž3Ÿç·óg«…JË/dÒx—Ø x½/óþjýûÈ»ïé¾p«žã<ðúGU¡™c'“žäpý;;Ù­¿"4LØ, 4NþìÈ/)Æ�”º•–{G˜ŒŒ±’ÔþŸ7ù�¼óg×\k2¿�EPUoO uÚxE“ùq6¼°fHµÀ¸oG‡jæ?WûAaU˜é+IõCÕ ,2aR/¶#¹Ò®ì8�;%Ä‘"&'ΉA*$�—O,`×»'E‘@òÒ\ÙÚ‰øí ¬êð™õ{–õ!œä�€ª`àqóvp°LŽwùÄ7Íèø`´ö:ÌçÖò­ì^ÍH…C«»ä@ðÇ¥¢×ñ%“Šs€ˆ¯-û%1£9¿tËOe�ùÑ&³ìZß#2< "‚pÝ[S”ìJá»­ÈtÝ…[é)o.vY»’¿3�§±«ŒÚ)¿e+htãR 4 ”d´ËäÑAp´•C�鵯*Éd4ê é±e)-cAë©��7�Š)òÁ/%äCÖ‡3^÷ãa0ça™P\ÞïøÛa–d‹|�RˆÃi¼h²Ùv¨uÃÑ.KjÀél—•ä ˆµeI æ\hc¢µšØÒîuMÞT;;0‹™8ÜÎCìÀ…Bm©ó‰D_ÕÔ cܰq­TÄ�ŽZô{‰¼º*ˆçzÊ\÷¿cÀÉ)Ç—FL@ÏÀuX祜dœEY.W·nûŠMò‹ý8}©xm&Óò¼‰ïÊÁíJ6M—·+U‚I¬*ÆEú�c4,ÿ”ù ñ-@üÀÄ*® íŒ¡Î�CúEŸjp^ßì™ðàújgÁRd±§7oδDÿ´óÿ'£r9:!ÜH$T±«"ÿM0¦�ëA‡ô'”…éÍRô�æ¡e/+ço§eXü‰Ö(0áf¢¯Õ¡A˃=¿MàTvµÁÒ+–øšENAö?B ìÈ�£šUñÁ[¢-ÎgF€Ê5™NViN,±R \‰§Ñ85Q¯Æg§mù!ò#ÿaiY¿¤À|x­4+‹.¶ÿ\L'æLÆÝ]—ø<q¯ÃŽóFñË›:W€l¾pÝi ì³`Ç”dï"Ÿæ|÷¯rŽL‰ןb ç ÚFãŸS“B”¬å–5Mœt4ÜsX¶�´�¤S+Fþ¤±bý 9¬w³†ÑÀNÔ´Ý÷#s²H�fgh>ÙŸEí;A‰ŽÛ²�¿Sà¿–RªóX¬qÖ™óD¹7�vΕFæþ ôØHrÙø¡ÿ[+ÌM}néÛ$ì–ËQ‰z@Ú/ }S7„.AÞ°pÂoR“ 41½¤$+Ͳ>鯬á~C^UIz�IÙT$õòX(R=ì»q é‹»�×›ü§­4ÜV ‚òÁ¹M@ÓfÆzÂ’Üã%øµ3,£øé/Ân‰V‹D›+#Â[Mh r[K^ÇÇÝƼ÷"›�†*Ë‹˜˜¸'=†‡Ù3Qò(”)7™.Û§]ÐÝë.!;uµ*ö©ï›h™&…ª'¹uyEªèÃJ�¯�ƒ7tàçRÖ뢹·ú3¯‚,6u^!évNÕJ!š­Òž5·?lÕ'tmd­‡ SÆk,V$ꢛKèg}L'¾ä˜\ñ&íüº:ŸÁ‹ª9¡ÜÐe|²ÛXrœú‚<µÒ`ïXÖâfˆRe'gR`)ièkÝ4uÜú›é3#tà¶D�{P–Óf—�ƒ�!ô¸ÂÌï¡¢«ò~ñ‡†TTƒuìçaؤùž0i ]tI«{ÉþðNX,ÐF‰îŽ�>“ñ ⶉŽ,؄Ҫ£ŒLYþC©•¡”ÿD­žpY0ꤠœÆÕ#®�MïB :BJ!Ÿ� Æ¡É~K¸4ìœ ÎfÀYž‹ûø.×¢Ñ/Ru ;j#riߪ¸7/ÊtPclüÇ7�Ñ 1oŸpÎÕ €z¡§.®…ÖÏÙ`bx+,¼`Üÿ}cX¤ÐaˆAbXý/wý]ªоÌaŠeÎ)KÍ�ƒ½—Æ?ÄþœÂa ×Yu:ÜZ&¤ynðahK?`’_é›u®,m|$¦º¼rEJÉpò·òl?„¥Ø5 û¡à–Š•…ò§¢†ÇæLw9lgßMO¶dtêP$¿jWÚÅPå§ÉÐ!ƒ2뛿j�徃,íjŠù�gõø¼Û)¼0¸ùCþjÿÜ«Õto<í …P÷v)iQþ†Cb` vªðš”)s4Áñ©Ö�Þ^wñ úruuNEIÄWÂt=ôÒ…Cæ˜téX«!NM© ˜ƒÈkã÷pû¿^¹¤u〴ÚÅv+&jéRë^nš±ú*Ç0 FPïå#wL�Ú'þ�¥¯1Å.ÿY0\Û]ƑעçñϹøì«¾@�#$¥µ­«ò)sîâ"¦ÃËVC¶ñŒòb«¹��“C4Íå‚RSi¨º8ÔÙ)€‰à׹ꅊ»“bϹìÁôà–Ú‚Úx»×ºö(ûí„Tu&§ê½ :°Ìö+Ží JX.509W0‚S0‚; 0  *†H†÷  010U Puppet CA: localhost0 130715002345Z 180715002345Z010U localhost-puppetdb0‚"0  *†H†÷ ‚0‚ ‚¦I?öpûÿP#�Î +iëÑ B´Ä?60Ü’ûùg÷ÖBååC!xO»'¦ÕF ›|pd¹hj^†ΛV0aÞW.o\ÓÏêô$£:S²{@‘‘‚H½q˜Özê 6oýìI_ŠÝøVw!c ³ï”p¶ÿoÑvÖ:E3%Ö€-Ž~ÇL§F þ£ñ+oåû`䫾�uðLN" C¬7$PS`�Ý…3Þ8Y´ŠiäB›€¡6’}Î j«‚@®-žAÚcÇŸ%´Xäªqù;6°5¸\òye§8$¬>¦>–zÜ4™Ã Ä``É9ÇšÞiçz ô£]¹C»$ÅQaǯ¹ñ�^|€7¬¨¨±µ~–�YR?Zi%?ÏYØÍôÄïDˆP>I*ý•/.¹8SöâÐ% š·J„&éšó[b‘bC¹Î´LþºžåöÔ麸@ìx0Ü®«÷þÖG`Ï rÝ 0´•×1�~éÂ.ߣ�›0�˜07 `†H†øB *(Puppet Ruby/OpenSSL Internal Certificate0Uÿ 0 U%ÿ0++0 Uÿ00Uã °ü¥¯!cFRkßM¡ed$C×0  *†H†÷  ‚°-•là6dŠ–¬ï¸8ªÿêpÔJaÃ:æçlüm§·FIu²Ow¢5<1$ƈ7ß w\zæQ™³ÃõyÞr.çd¾²m5õDt±�nЫç¶ÖN¾ËÀÈÂ>JF�$WÖÉG‡êj7$‡€èdF’.NÚÐÊrm7 ð¶úæ¶Ì¹d„UðÔ ÙÑ‚A™ ‹b¢›Û¢H#/¸¾·Û›QŠvO(ãrà¬�W™ÏÿBøü�ƒÑHCÚ섘Ů ?æ&r‹ÛïÿÉãUÛ†F— 8Ç&ôÎõûšUµµ5\ÇÍ19Tµ±J#ðþ s‰;V£ `¨“[‚o6®ñÊW X¥Za¨i¨¥B¢Ç=+MŒoåÝ��<>s[vš„®“­àM5„‚ÜÛ©Ü ·(S¼ó#”1ÀÔ3<‹¨ìÙ¥X’•DÉÜÏÅQwEBùÑ™&&‘ŸÙHMМ‡Ñ*ßIsÜ¡³† jâ$š �tjàÏI7ÚA)ûbœhüZtʆòMÇR�Æ9èN^ ™UÐÏD¬ ð: Ú�„© ÉPKõRÈèØR¯•srN7еýÔ[f$6“—Ýý¢ãº�[�Õ·(‹ ÍvuøåçkŽ=¦aýÃú!ð˜{ÍnÀ<óh¢žxtîù«P«25Œ¶æ2dƒÖÖvßæ, ¦°U9ƒêhÁc÷ìÓ«¦ŽÎúþëÓÛýTÂKîê+kqpŒÈ�ÓÐ+­nÎ7”·öøW³ú•®u¶O÷¹hA‡ŸßÅ‘KBB…e7óØXGZ ypî ­ßX«`¿ÖN�ÎH$s,zù€î®myGvÆ{´È9ôëò¾á¾¯p¨@…áÎ ™TNÿɹ¼Œ+Q¢­/Û' ºv,–` A™¯†´=‡ÃŸbÈx¡ZÚ�ëðéÒ}±*½!§jJ™K+’YõÈ.$2Qd‰~]M×(n†¥¾ƒQØùγOlz¶Í5/Í)ƒ¸.2OÝräP Ðnø§+�§TâµgÞ”Í�ì@û$ô“"J›ЪËó…£C?åæ,ÂVØ ÖÙÔ�r& �Z“›zn÷_‘=ÚR3æŽ8LÐH‘(«C¥3"yûiR� 3œý”'øúEæîÒ[Οµ%!ÈÅiWÂoЫüDÚ¤ ±±k\UÓ)+�Ó §ŽÑ#‹Â´š¸ÎŒy¦Fš%¿¥†u<˜òΪŲ•¼é¬¢3¸? ;¹lÏ4 \°ØøûÉ–.ƒdЦ75®ÜìR#n_Z/òÚ�Ä4o§`Á…/7U¾‡4¼ïAèãi\’‡ÄMµË¯åЄȅ¾h ¬ $ÌÉ­y /¹óq …¾Ãå1;�+`šY�^Ð&ø6VóŒó!úóÌZzÑùð.†/ñ\GÁkÊ-�qtZ>¸¹�¡ŸbÈýï�üjM‰yóxx,‹•’VíÔ‚:•>çÞyÂt|/&|tpô/¹§8¨�ΫSÀ³Î)rI³t�Ãô‘�ß�Õ#m^ËNù‹�œ€´{ÀC†Pr,5ÃT JØÉ\¾Wi§ª?ƒ]äÌ…º�.%V¶J8m=”fm¾ °·BA¤ªCk;Á›7WÁÝaE¥>—1¼D2m•×jrÚù4HE4¹H0~�=÷"µó|´Âú[a'„+i=|¸ ©ú©<Èm}…T•H�vIP?„s‘fJ£bålœ´ºeéÖ³‰;Å~f€Ý‰®™{Zn$—R¤.Ø-=pNŠV“s˜œÙä F0�¶0 *†H†÷  0d *†H†÷  0W@§ ¸XÕ4Oß@–öý B/ÇPqȹ�¡Þã"sW‹º“o´ÅÚ5ý\…{xäÓÄÄ~ò€”ÌtëH xúÄIâwil@@0 *†H†÷  @‰Ë„qˆGù‚·˜ÙÜô9óîͰÁ“1`Íu{×r#BœÕ¶^ä_`öè <‘”Ÿ%V˜(¥X? gôVoOpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/config/jetty/ssl/truststore.jks000066400000000000000000000025721527232126200326240ustar00rootroot00000000000000þíþí puppetdb caEã ‡X.50960‚20‚ 0  *†H†÷  010U Puppet CA: localhost0 140214180907Z 190214180907Z010U Puppet CA: localhost0‚"0  *†H†÷ ‚0‚ ‚æö' Ÿ9“ªœP\Öêý0Ý™XY`©ÁÐ_›Æ ¢ø=ëskjìrƒêmñ¡‹�ÀñœädùÇS’�üðñ Ý¡Ù¹•…¬jê �ºb¸õa™80‡gäÛÃu¤Õ~é/­�–ÔµõJ°Ýøí|‡ *òšfÿ9@ÄüŽÿ¾� ¹(þ 0à Àù`éW}ýGÁ=VmÃûÊ7‰C™©%Ð[ÝÏ*é‰÷ðÒá¬ìPÄu'@ë¼–}úo« í€@Gé׸³Ö¬#2dóòÛ%™Žyͤ–Ésj�¼î�FêJã§dãCÿMöJ¤\Jû¿mCØçöHt(¯4^öUÎÀíÁ`K¾,©’Ðç�ªê 2µk/n€“›€�^ŽÉi�BŸ–Omõ|Gy.Q¨÷Ãæ9"ÖWg³S�¤;wlÈIé£ìÌde{|¶õ¥P•˜%*nqµx7S…]:‹Ýiæò ãðÀ£ht÷Jˆ§Ã:7_J‚� ºþܦ0~ÇÜaç­=‡ý³cWS…£ˆ{ír~”�ùðpim3’¨mK²j "3§qŠí‘·nÊ(œôB¾K4bÆvkßIJ3(˜Ì¸Z‚â¹vBëH|Kêy© ��™—/ I «¬€nH’š £y0w05 `†H†øB (Puppet Ruby/OpenSSL Internal Certificate0Uÿ0Uÿ0ÿ0UYËpô½¢íæž*ò8„dDh_0  *†H†÷  ‚dw2jxê ¯šä°bm–0¤Z35YhÜ>‚ÞÁ×xmX*@ la�Vt’È„´âØøý�Þxõ%×·d{;É4$«t°XˆQHÂQÌ@ŽÒô¬¾æ¼ž�1_’º6ûøCS0¾úúеwµÓ¨|št‰8‡:xŨX—þAa®ÎKä­.‹‹àÒ(J¯ª_ ÅÕ ÔãÄ(j+O¾½ÒÃÃÿpð<õF¨oª#"/êî[¹R爵¢j®8nx‹ü‡“mVèT‹4qo‘°WŸŽÁÜ.½©¼ú¿Š”OþÀ��Î&†Boˆ©âb#¦Ðz wd^T_`š"FlÍ/Û$;þßkH'éw÷„`Ç\YÉÒ|Gÿ8à?¶.ãž–©Õíº²èëôÍ%ªÇa d¤KEø¢Jj&}Ó4㮨V¶=w-µýñÅUs>ŸÂ/±/‘IÔÛ¤ ¹—A�göÛ&Uˆ¤jÛgƒœÏß®Ê19nF² ÇÒU¥óæt•�È¿:zÛ¸$y9rmw»ñE”õæmœ÷iEmÕeº…ÈŒÐØ RÍÅF¸ÅeÚ�ˆ/[#+È͈ ø¦MãP¼Ü/S:8Ã$óóÓrfh<Þ ¢Rr¤­£j÷’ó’ªùµ=':‚w†‘³ïB”ÑÕÇ6„À«q–ezB�] à~²h1V6Jz#¿š*ÉìȬvÀ9eÕ êÀ›AOpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/helloWorld.war000066400000000000000000000041441527232126200272730ustar00rootroot00000000000000PK RN\\ META-INF/þÊPKRN\\META-INF/MANIFEST.MFóMÌËLK-.Ñ K-*ÎÌϳR0Ô3àår.JM,IMÑuª´R0Šè(h¸¤&e&æiòrñrPK©›e/87PK Rn—[WEB-INF/PK cn—[WEB-INF/classes/PKMN\\"WEB-INF/classes/HelloServlet.class�RÛnÓ@=››�ÄmHÚPh)$-Ð\»\xˆ•— (RU*R¥¯8ñ*5¸Þ`oªö³x *|…˜u¢´B•¨-ÍxgΜ3ž�ß~þð¯sH i e!� Cå‹óÕ •Ã#žûBñS¥Æ|ŸLo`ÈØ^à©.C²Vïç`"k g!‹ÁÚ¾/д+ßk߯ü�÷“ø6‘êÜ�e‰N½ob™!«Ä…F�ùyÜCÑ@É VjwebXŽ„Ú“��:¾S ¬>w¸ï#ÞS¡ŒHO Ü·°†$;ê$ô”ÖjõÜ“üˆ°óDÇĺ—î­›Ã#lxlá‰nnå<ƒ1Ö'?0Qeàö©pÜ®­<å‹n<ØÊ‰ }·2ïßæ³”Íc ‰m†u{ ÝË›èjÕæqÌÄ3R°ù¢� 5}çé¡/õR{Ò%W8ðq89ˆðØøɸòHFt�¹·C1VMÍÀî�¿øðq‘1ðâ–5š·¼@WON¡xçi…âͽÙÕ¬¨Òf% Ÿ$˜^N²u:m’gäÓ�`ß郡A63 ’m¢B ݦÒ$y£ÑlMa\ƒs1³IEY´ââÚà”Í/Š?“O‘oµJKW($кB™á°]z8ÅF»T‰íVlŸj;Åók…-bq™XB�Þ2­ÎŠôW%ìÐ~6±ú�òK:%ðê/PKöÒªq šPK Qn—[ WEB-INF/src/PKQn—[WEB-INF/src/HelloServlet.javaµ‘ÁNÃ0 †ïy ¯§‚¦öVvA81ÒÎ]kÑ@g‰[6¡½;nÖ¢Á¦Ý¸~ÿg痣׎<Ã{Ù•™¦ìz¦ôH>JÏeÐwùBÒ0»>V®]]AeÊà�¡—ƒ¸e´µ@Q¦¾À0Ñ‘®¡¦†ôÈyÆM‹ÂÁyÈy`¸¦AL&¬;­i~"�Á×4MÖÜgÆíù]žOùÛózS°†Tjò Ë‘�äœZvmJðí 7 Ðüunà—¥w³]ž�¨Œt½°Y¸°"࢒d|§j,žP)öƩŠmñ�­¬U2Ž.øHÙZ‘J'í™-ÚŠ Í z+�ö uxŒÂG!–º£BŸ�ãø¯ # # This properties file appends to the master security properties file. # If both properties files specify values for the same key, the value # from the command-line properties file is selected, as it is the last # one loaded. # # Also, if you specify # # -Djava.security.properties== (2 equals), # # then that properties file completely overrides the master security # properties file. # # To disable the ability to specify an additional properties file from # the command line, set the key security.overridePropertiesFile # to false in the master security properties file. It is set to true # by default. # In this file, various security properties are set for use by # java.security classes. This is where users can statically register # Cryptography Package Providers ("providers" for short). The term # "provider" refers to a package or set of packages that supply a # concrete implementation of a subset of the cryptography aspects of # the Java Security API. A provider may, for example, implement one or # more digital signature algorithms or message digest algorithms. # # Each provider must implement a subclass of the Provider class. # To register a provider in this master security properties file, # specify the provider and priority in the format # # security.provider.= # # This declares a provider, and specifies its preference # order n. The preference order is the order in which providers are # searched for requested algorithms (when no specific provider is # requested). The order is 1-based; 1 is the most preferred, followed # by 2, and so on. # # must specify the name of the Provider as passed to its super # class java.security.Provider constructor. This is for providers loaded # through the ServiceLoader mechanism. # # must specify the subclass of the Provider class whose # constructor sets the values of various properties that are required # for the Java Security API to look up the algorithms or other # facilities implemented by the provider. This is for providers loaded # through classpath. # # Note: Providers can be dynamically registered instead by calls to # either the addProvider or insertProviderAt method in the Security # class. # # List of providers and their preference orders (see above): # security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider fips:org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.3=SUN security.provider.4=SunRsaSign #security.provider.5=SunEC #security.provider.6=SunJSSE #security.provider.7=SunJCE #security.provider.8=SunJGSS #security.provider.9=SunSASL #security.provider.10=XMLDSig #security.provider.11=SunPCSC #security.provider.12=JdkLDAP #security.provider.13=JdkSASL #security.provider.14=SunPKCS11 # # A list of preferred providers for specific algorithms. These providers will # be searched for matching algorithms before the list of registered providers. # Entries containing errors (parsing, etc) will be ignored. Use the # -Djava.security.debug=jca property to debug these errors. # # The property is a comma-separated list of serviceType.algorithm:provider # entries. The serviceType (example: "MessageDigest") is optional, and if # not specified, the algorithm applies to all service types that support it. # The algorithm is the standard algorithm name or transformation. # Transformations can be specified in their full standard name # (ex: AES/CBC/PKCS5Padding), or as partial matches (ex: AES, AES/CBC). # The provider is the name of the provider. Any provider that does not # also appear in the registered list will be ignored. # # There is a special serviceType for this property only to group a set of # algorithms together. The type is "Group" and is followed by an algorithm # keyword. Groups are to simplify and lessen the entries on the property # line. Current groups are: # Group.SHA2 = SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 # Group.HmacSHA2 = HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512 # Group.SHA2RSA = SHA224withRSA, SHA256withRSA, SHA384withRSA, SHA512withRSA # Group.SHA2DSA = SHA224withDSA, SHA256withDSA, SHA384withDSA, SHA512withDSA # Group.SHA2ECDSA = SHA224withECDSA, SHA256withECDSA, SHA384withECDSA, \ # SHA512withECDSA # Group.SHA3 = SHA3-224, SHA3-256, SHA3-384, SHA3-512 # Group.HmacSHA3 = HmacSHA3-224, HmacSHA3-256, HmacSHA3-384, HmacSHA3-512 # # Example: # jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \ # MessageDigest.SHA-256:SUN, Group.HmacSHA2:SunJCE # #jdk.security.provider.preferred= # # Sun Provider SecureRandom seed source. # # Select the primary source of seed data for the "NativePRNG", "SHA1PRNG" # and "DRBG" SecureRandom implementations in the "Sun" provider. # (Other SecureRandom implementations might also use this property.) # # On Unix-like systems (for example, Solaris/Linux/MacOS), the # "NativePRNG", "SHA1PRNG" and "DRBG" implementations obtains seed data from # special device files such as file:/dev/random. # # On Windows systems, specifying the URLs "file:/dev/random" or # "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding # mechanism for SHA1PRNG and DRBG. # # By default, an attempt is made to use the entropy gathering device # specified by the "securerandom.source" Security property. If an # exception occurs while accessing the specified URL: # # NativePRNG: # a default value of /dev/random will be used. If neither # are available, the implementation will be disabled. # "file" is the only currently supported protocol type. # # SHA1PRNG and DRBG: # the traditional system/thread activity algorithm will be used. # # The entropy gathering device can also be specified with the System # property "java.security.egd". For example: # # % java -Djava.security.egd=file:/dev/random MainClass # # Specifying this System property will override the # "securerandom.source" Security property. # # In addition, if "file:/dev/random" or "file:/dev/urandom" is # specified, the "NativePRNG" implementation will be more preferred than # DRBG and SHA1PRNG in the Sun provider. # securerandom.source=file:/dev/random # # A list of known strong SecureRandom implementations. # # To help guide applications in selecting a suitable strong # java.security.SecureRandom implementation, Java distributions should # indicate a list of known strong implementations using the property. # # This is a comma-separated list of algorithm and/or algorithm:provider # entries. # securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN # # Sun provider DRBG configuration and default instantiation request. # # NIST SP 800-90Ar1 lists several DRBG mechanisms. Each can be configured # with a DRBG algorithm name, and can be instantiated with a security strength, # prediction resistance support, etc. This property defines the configuration # and the default instantiation request of "DRBG" SecureRandom implementations # in the SUN provider. (Other DRBG implementations can also use this property.) # Applications can request different instantiation parameters like security # strength, capability, personalization string using one of the # getInstance(...,SecureRandomParameters,...) methods with a # DrbgParameters.Instantiation argument, but other settings such as the # mechanism and DRBG algorithm names are not currently configurable by any API. # # Please note that the SUN implementation of DRBG always supports reseeding. # # The value of this property is a comma-separated list of all configurable # aspects. The aspects can appear in any order but the same aspect can only # appear at most once. Its BNF-style definition is: # # Value: # aspect { "," aspect } # # aspect: # mech_name | algorithm_name | strength | capability | df # # // The DRBG mechanism to use. Default "Hash_DRBG" # mech_name: # "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG" # # // The DRBG algorithm name. The "SHA-***" names are for Hash_DRBG and # // HMAC_DRBG, default "SHA-256". The "AES-***" names are for CTR_DRBG, # // default "AES-128" when using the limited cryptographic or "AES-256" # // when using the unlimited. # algorithm_name: # "SHA-224" | "SHA-512/224" | "SHA-256" | # "SHA-512/256" | "SHA-384" | "SHA-512" | # "AES-128" | "AES-192" | "AES-256" # # // Security strength requested. Default "128" # strength: # "112" | "128" | "192" | "256" # # // Prediction resistance and reseeding request. Default "none" # // "pr_and_reseed" - Both prediction resistance and reseeding # // support requested # // "reseed_only" - Only reseeding support requested # // "none" - Neither prediction resistance not reseeding # // support requested # pr: # "pr_and_reseed" | "reseed_only" | "none" # # // Whether a derivation function should be used. only applicable # // to CTR_DRBG. Default "use_df" # df: # "use_df" | "no_df" # # Examples, # securerandom.drbg.config=Hash_DRBG,SHA-224,112,none # securerandom.drbg.config=CTR_DRBG,AES-256,192,pr_and_reseed,use_df # # The default value is an empty string, which is equivalent to # securerandom.drbg.config=Hash_DRBG,SHA-256,128,none # securerandom.drbg.config= # # Class to instantiate as the javax.security.auth.login.Configuration # provider. # login.configuration.provider=sun.security.provider.ConfigFile # # Default login configuration file # #login.config.url.1=file:${user.home}/.java.login.config # # Class to instantiate as the system Policy. This is the name of the class # that will be used as the Policy object. The system class loader is used to # locate this class. # policy.provider=sun.security.provider.PolicyFile # The default is to have a single system-wide policy file, # and a policy file in the user's home directory. # policy.url.1=file:${java.home}/conf/security/java.policy policy.url.2=file:${user.home}/.java.policy # whether or not we expand properties in the policy file # if this is set to false, properties (${...}) will not be expanded in policy # files. # policy.expandProperties=true # whether or not we allow an extra policy to be passed on the command line # with -Djava.security.policy=somefile. Comment out this line to disable # this feature. # policy.allowSystemProperty=true # whether or not we look into the IdentityScope for trusted Identities # when encountering a 1.1 signed JAR file. If the identity is found # and is trusted, we grant it AllPermission. Note: the default policy # provider (sun.security.provider.PolicyFile) does not support this property. # policy.ignoreIdentityScope=false # # Default keystore type. # keystore.type=pkcs12 # # Controls compatibility mode for JKS and PKCS12 keystore types. # # When set to 'true', both JKS and PKCS12 keystore types support loading # keystore files in either JKS or PKCS12 format. When set to 'false' the # JKS keystore type supports loading only JKS keystore files and the PKCS12 # keystore type supports loading only PKCS12 keystore files. # keystore.type.compat=true # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when passed to the # SecurityManager::checkPackageAccess method unless the corresponding # RuntimePermission("accessClassInPackage."+package) has been granted. # package.access=sun.misc.,\ sun.reflect.,\ org.GNOME.Accessibility. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when passed to the # SecurityManager::checkPackageDefinition method unless the corresponding # RuntimePermission("defineClassInPackage."+package) has been granted. # # By default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # package.definition=sun.misc.,\ sun.reflect. # # Determines whether this properties file can be appended to # or overridden on the command line via -Djava.security.properties # security.overridePropertiesFile=true # # Determines the default key and trust manager factory algorithms for # the javax.net.ssl package. # ssl.KeyManagerFactory.algorithm=BCFKS ssl.TrustManagerFactory.algorithm=PKIX # # The Java-level namelookup cache policy for successful lookups: # # any negative value: caching forever # any positive value: the number of seconds to cache an address for # zero: do not cache # # default value is forever (FOREVER). For security reasons, this # caching is made forever when a security manager is set. When a security # manager is not set, the default behavior in this implementation # is to cache for 30 seconds. # # NOTE: setting this to anything other than the default value can have # serious security implications. Do not set it unless # you are sure you are not exposed to DNS spoofing attack. # #networkaddress.cache.ttl=-1 # The Java-level namelookup cache policy for failed lookups: # # any negative value: cache forever # any positive value: the number of seconds to cache negative lookup results # zero: do not cache # # In some Microsoft Windows networking environments that employ # the WINS name service in addition to DNS, name service lookups # that fail may take a noticeably long time to return (approx. 5 seconds). # For this reason the default caching policy is to maintain these # results for 10 seconds. # networkaddress.cache.negative.ttl=10 # # Properties to configure OCSP for certificate revocation checking # # Enable OCSP # # By default, OCSP is not used for certificate revocation checking. # This property enables the use of OCSP when set to the value "true". # # NOTE: SocketPermission is required to connect to an OCSP responder. # # Example, # ocsp.enable=true # # Location of the OCSP responder # # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the # Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, # ocsp.responderURL=http://ocsp.example.net:80 # # Subject name of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # distinguished name (defined in RFC 2253) which identifies a certificate in # the set of certificates supplied during cert path validation. In cases where # the subject name alone is not sufficient to uniquely identify the certificate # then both the "ocsp.responderCertIssuerName" and # "ocsp.responderCertSerialNumber" properties must be used instead. When this # property is set then those two properties are ignored. # # Example, # ocsp.responderCertSubjectName=CN=OCSP Responder, O=XYZ Corp # # Issuer name of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # distinguished name (defined in RFC 2253) which identifies a certificate in # the set of certificates supplied during cert path validation. When this # property is set then the "ocsp.responderCertSerialNumber" property must also # be set. When the "ocsp.responderCertSubjectName" property is set then this # property is ignored. # # Example, # ocsp.responderCertIssuerName=CN=Enterprise CA, O=XYZ Corp # # Serial number of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # of hexadecimal digits (colon or space separators may be present) which # identifies a certificate in the set of certificates supplied during cert path # validation. When this property is set then the "ocsp.responderCertIssuerName" # property must also be set. When the "ocsp.responderCertSubjectName" property # is set then this property is ignored. # # Example, # ocsp.responderCertSerialNumber=2A:FF:00 # # Policy for failed Kerberos KDC lookups: # # When a KDC is unavailable (network error, service failure, etc), it is # put inside a blacklist and accessed less often for future requests. The # value (case-insensitive) for this policy can be: # # tryLast # KDCs in the blacklist are always tried after those not on the list. # # tryLess[:max_retries,timeout] # KDCs in the blacklist are still tried by their order in the configuration, # but with smaller max_retries and timeout values. max_retries and timeout # are optional numerical parameters (default 1 and 5000, which means once # and 5 seconds). Please notes that if any of the values defined here is # more than what is defined in krb5.conf, it will be ignored. # # Whenever a KDC is detected as available, it is removed from the blacklist. # The blacklist is reset when krb5.conf is reloaded. You can add # refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is # reloaded whenever a JAAS authentication is attempted. # # Example, # krb5.kdc.bad.policy = tryLast # krb5.kdc.bad.policy = tryLess:2,2000 # krb5.kdc.bad.policy = tryLast # # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable # for certification path building and validation. For example, "MD2" is # generally no longer considered to be a secure hash algorithm. This section # describes the mechanism for disabling algorithms based on algorithm name # and/or key length. This includes algorithms used in certificates, as well # as revocation information such as CRLs and signed OCSP Responses. # The syntax of the disabled algorithm string is described as follows: # DisabledAlgorithms: # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: # AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: # KeySizeConstraint | CAConstraint | DenyAfterConstraint | # UsageConstraint # # KeySizeConstraint: # keySize Operator KeyLength # # Operator: # <= | < | == | != | >= | > # # KeyLength: # Integer value of the algorithm's key length in bits # # CAConstraint: # jdkCA # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # # UsageConstraint: # usage [TLSServer] [TLSClient] [SignedJAR] # # The "AlgorithmName" is the standard algorithm name of the disabled # algorithm. See "Java Cryptography Architecture Standard Algorithm Name # Documentation" for information about Standard Algorithm Names. Matching # is performed using a case-insensitive sub-element matching rule. (For # example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and # "ECDSA" for signatures.) If the assertion "AlgorithmName" is a # sub-element of the certificate algorithm name, the algorithm will be # rejected during certification path building and validation. For example, # the assertion algorithm name "DSA" will disable all certificate algorithms # that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion # will not disable algorithms related to "ECDSA". # # A "Constraint" defines restrictions on the keys and/or certificates for # a specified AlgorithmName: # # KeySizeConstraint: # keySize Operator KeyLength # The constraint requires a key of a valid size range if the # "AlgorithmName" is of a key algorithm. The "KeyLength" indicates # the key size specified in number of bits. For example, # "RSA keySize <= 1024" indicates that any RSA key with key size less # than or equal to 1024 bits should be disabled, and # "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key # with key size less than 1024 or greater than 2048 should be disabled. # This constraint is only used on algorithms that have a key size. # # CAConstraint: # jdkCA # This constraint prohibits the specified algorithm only if the # algorithm is used in a certificate chain that terminates at a marked # trust anchor in the lib/security/cacerts keystore. If the jdkCA # constraint is not set, then all chains using the specified algorithm # are restricted. jdkCA may only be used once in a DisabledAlgorithm # expression. # Example: To apply this constraint to SHA-1 certificates, include # the following: "SHA1 jdkCA" # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # This constraint prohibits a certificate with the specified algorithm # from being used after the date regardless of the certificate's # validity. JAR files that are signed and timestamped before the # constraint date with certificates containing the disabled algorithm # will not be restricted. The date is processed in the UTC timezone. # This constraint can only be used once in a DisabledAlgorithm # expression. # Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020, # use the following: "RSA keySize == 2048 & denyAfter 2020-02-03" # # UsageConstraint: # usage [TLSServer] [TLSClient] [SignedJAR] # This constraint prohibits the specified algorithm for # a specified usage. This should be used when disabling an algorithm # for all usages is not practical. 'TLSServer' restricts the algorithm # in TLS server certificate chains when server authentication is # performed. 'TLSClient' restricts the algorithm in TLS client # certificate chains when client authentication is performed. # 'SignedJAR' constrains use of certificates in signed jar files. # The usage type follows the keyword and more than one usage type can # be specified with a whitespace delimiter. # Example: "SHA1 usage TLSServer TLSClient" # # When an algorithm must satisfy more than one constraint, it must be # delimited by an ampersand '&'. For example, to restrict certificates in a # chain that terminate at a distribution provided trust anchor and contain # RSA keys that are less than or equal to 1024 bits, add the following # constraint: "RSA keySize <= 1024 & jdkCA". # # All DisabledAlgorithms expressions are processed in the order defined in the # property. This requires lower keysize constraints to be specified # before larger keysize constraints of the same algorithm. For example: # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". # # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # # Note: This property is currently used by Oracle's PKIX implementation. It # is not guaranteed to be examined and used by other implementations. # # Example: # jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 # # jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \ RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224 # # Algorithm restrictions for signed JAR files # # In some environments, certain algorithms or key lengths may be undesirable # for signed JAR validation. For example, "MD2" is generally no longer # considered to be a secure hash algorithm. This section describes the # mechanism for disabling algorithms based on algorithm name and/or key length. # JARs signed with any of the disabled algorithms or key sizes will be treated # as unsigned. # # The syntax of the disabled algorithm string is described as follows: # DisabledAlgorithms: # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: # AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: # KeySizeConstraint | DenyAfterConstraint # # KeySizeConstraint: # keySize Operator KeyLength # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # # Operator: # <= | < | == | != | >= | > # # KeyLength: # Integer value of the algorithm's key length in bits # # Note: This property is currently used by the JDK Reference # implementation. It is not guaranteed to be examined and used by other # implementations. # # See "jdk.certpath.disabledAlgorithms" for syntax descriptions. # jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ DSA keySize < 1024 # # Algorithm restrictions for Secure Socket Layer/Transport Layer Security # (SSL/TLS/DTLS) processing # # In some environments, certain algorithms or key lengths may be undesirable # when using SSL/TLS/DTLS. This section describes the mechanism for disabling # algorithms during SSL/TLS/DTLS security parameters negotiation, including # protocol version negotiation, cipher suites selection, peer authentication # and key exchange mechanisms. # # Disabled algorithms will not be negotiated for SSL/TLS connections, even # if they are enabled explicitly in an application. # # For PKI-based peer authentication and key exchange mechanisms, this list # of disabled algorithms will also be checked during certification path # building and validation, including algorithms used in certificates, as # well as revocation information such as CRLs and signed OCSP Responses. # This is in addition to the jdk.certpath.disabledAlgorithms property above. # # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ EC keySize < 224, 3DES_EDE_CBC, anon, NULL # # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) # processing in JSSE implementation. # # In some environments, a certain algorithm may be undesirable but it # cannot be disabled because of its use in legacy applications. Legacy # algorithms may still be supported, but applications should not use them # as the security strength of legacy algorithms are usually not strong enough # in practice. # # During SSL/TLS security parameters negotiation, legacy algorithms will # not be negotiated unless there are no other candidates. # # The syntax of the legacy algorithms string is described as this Java # BNF-style: # LegacyAlgorithms: # " LegacyAlgorithm { , LegacyAlgorithm } " # # LegacyAlgorithm: # AlgorithmName (standard JSSE algorithm name) # # See the specification of security property "jdk.certpath.disabledAlgorithms" # for the syntax and description of the "AlgorithmName" notation. # # Per SSL/TLS specifications, cipher suites have the form: # SSL_KeyExchangeAlg_WITH_CipherAlg_MacAlg # or # TLS_KeyExchangeAlg_WITH_CipherAlg_MacAlg # # For example, the cipher suite TLS_RSA_WITH_AES_128_CBC_SHA uses RSA as the # key exchange algorithm, AES_128_CBC (128 bits AES cipher algorithm in CBC # mode) as the cipher (encryption) algorithm, and SHA-1 as the message digest # algorithm for HMAC. # # The LegacyAlgorithm can be one of the following standard algorithm names: # 1. JSSE cipher suite name, e.g., TLS_RSA_WITH_AES_128_CBC_SHA # 2. JSSE key exchange algorithm name, e.g., RSA # 3. JSSE cipher (encryption) algorithm name, e.g., AES_128_CBC # 4. JSSE message digest algorithm name, e.g., SHA # # See SSL/TLS specifications and "Java Cryptography Architecture Standard # Algorithm Name Documentation" for information about the algorithm names. # # Note: If a legacy algorithm is also restricted through the # jdk.tls.disabledAlgorithms property or the # java.security.AlgorithmConstraints API (See # javax.net.ssl.SSLParameters.setAlgorithmConstraints()), # then the algorithm is completely disabled and will not be negotiated. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # There is no guarantee the property will continue to exist or be of the # same syntax in future releases. # # Example: # jdk.tls.legacyAlgorithms=DH_anon, DES_CBC, SSL_RSA_WITH_RC4_128_MD5 # jdk.tls.legacyAlgorithms= \ K_NULL, C_NULL, M_NULL, \ DH_anon, ECDH_anon, \ RC4_128, RC4_40, DES_CBC, DES40_CBC, \ 3DES_EDE_CBC # # The pre-defined default finite field Diffie-Hellman ephemeral (DHE) # parameters for Transport Layer Security (SSL/TLS/DTLS) processing. # # In traditional SSL/TLS/DTLS connections where finite field DHE parameters # negotiation mechanism is not used, the server offers the client group # parameters, base generator g and prime modulus p, for DHE key exchange. # It is recommended to use dynamic group parameters. This property defines # a mechanism that allows you to specify custom group parameters. # # The syntax of this property string is described as this Java BNF-style: # DefaultDHEParameters: # DefinedDHEParameters { , DefinedDHEParameters } # # DefinedDHEParameters: # "{" DHEPrimeModulus , DHEBaseGenerator "}" # # DHEPrimeModulus: # HexadecimalDigits # # DHEBaseGenerator: # HexadecimalDigits # # HexadecimalDigits: # HexadecimalDigit { HexadecimalDigit } # # HexadecimalDigit: one of # 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f # # Whitespace characters are ignored. # # The "DefinedDHEParameters" defines the custom group parameters, prime # modulus p and base generator g, for a particular size of prime modulus p. # The "DHEPrimeModulus" defines the hexadecimal prime modulus p, and the # "DHEBaseGenerator" defines the hexadecimal base generator g of a group # parameter. It is recommended to use safe primes for the custom group # parameters. # # If this property is not defined or the value is empty, the underlying JSSE # provider's default group parameter is used for each connection. # # If the property value does not follow the grammar, or a particular group # parameter is not valid, the connection will fall back and use the # underlying JSSE provider's default group parameter. # # Note: This property is currently used by OpenJDK's JSSE implementation. It # is not guaranteed to be examined and used by other implementations. # # Example: # jdk.tls.server.defaultDHEParameters= # { \ # FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 \ # 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD \ # EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 \ # E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED \ # EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 \ # FFFFFFFF FFFFFFFF, 2} # # TLS key limits on symmetric cryptographic algorithms # # This security property sets limits on algorithms key usage in TLS 1.3. # When the amount of data encrypted exceeds the algorithm value listed below, # a KeyUpdate message will trigger a key change. This is for symmetric ciphers # with TLS 1.3 only. # # The syntax for the property is described below: # KeyLimits: # " KeyLimit { , KeyLimit } " # # WeakKeyLimit: # AlgorithmName Action Length # # AlgorithmName: # A full algorithm transformation. # # Action: # KeyUpdate # # Length: # The amount of encrypted data in a session before the Action occurs # This value may be an integer value in bytes, or as a power of two, 2^29. # # KeyUpdate: # The TLS 1.3 KeyUpdate handshake process begins when the Length amount # is fulfilled. # # Note: This property is currently used by OpenJDK's JSSE implementation. It # is not guaranteed to be examined and used by other implementations. # jdk.tls.keyLimits=AES/GCM/NoPadding KeyUpdate 2^37 # # Cryptographic Jurisdiction Policy defaults # # Import and export control rules on cryptographic software vary from # country to country. By default, Java provides two different sets of # cryptographic policy files[1]: # # unlimited: These policy files contain no restrictions on cryptographic # strengths or algorithms # # limited: These policy files contain more restricted cryptographic # strengths # # The default setting is determined by the value of the "crypto.policy" # Security property below. If your country or usage requires the # traditional restrictive policy, the "limited" Java cryptographic # policy is still available and may be appropriate for your environment. # # If you have restrictions that do not fit either use case mentioned # above, Java provides the capability to customize these policy files. # The "crypto.policy" security property points to a subdirectory # within /conf/security/policy/ which can be customized. # Please see the /conf/security/policy/README.txt file or consult # the Java Security Guide/JCA documentation for more information. # # YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY # TO DETERMINE THE EXACT REQUIREMENTS. # # [1] Please note that the JCE for Java SE, including the JCE framework, # cryptographic policy files, and standard JCE providers provided with # the Java SE, have been reviewed and approved for export as mass market # encryption item by the US Bureau of Industry and Security. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # crypto.policy=unlimited # # The policy for the XML Signature secure validation mode. The mode is # enabled by setting the property "org.jcp.xml.dsig.secureValidation" to # true with the javax.xml.crypto.XMLCryptoContext.setProperty() method, # or by running the code with a SecurityManager. # # Policy: # Constraint {"," Constraint } # Constraint: # AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint | # ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint # AlgConstraint # "disallowAlg" Uri # MaxTransformsConstraint: # "maxTransforms" Integer # MaxReferencesConstraint: # "maxReferences" Integer # ReferenceUriSchemeConstraint: # "disallowReferenceUriSchemes" String { String } # KeySizeConstraint: # "minKeySize" KeyAlg Integer # OtherConstraint: # "noDuplicateIds" | "noRetrievalMethodLoops" # # For AlgConstraint, Uri is the algorithm URI String that is not allowed. # See the XML Signature Recommendation for more information on algorithm # URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm # name of the key type (ex: "RSA"). If the MaxTransformsConstraint, # MaxReferencesConstraint or KeySizeConstraint (for the same key type) is # specified more than once, only the last entry is enforced. # # Note: This property is currently used by the JDK Reference implementation. It # is not guaranteed to be examined and used by other implementations. # jdk.xml.dsig.secureValidationPolicy=\ disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,\ maxTransforms 5,\ maxReferences 30,\ disallowReferenceUriSchemes file http https,\ minKeySize RSA 1024,\ minKeySize DSA 1024,\ minKeySize EC 224,\ noDuplicateIds,\ noRetrievalMethodLoops # # Serialization process-wide filter # # A filter, if configured, is used by java.io.ObjectInputStream during # deserialization to check the contents of the stream. # A filter is configured as a sequence of patterns, each pattern is either # matched against the name of a class in the stream or defines a limit. # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # # If the system property jdk.serialFilter is also specified, it supersedes # the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. # Limits are checked before classes regardless of the order in the # sequence of patterns. # If any of the limits are exceeded, the filter status is REJECTED. # # maxdepth=value - the maximum depth of a graph # maxrefs=value - the maximum number of internal references # maxbytes=value - the maximum number of bytes in the input stream # maxarray=value - the maximum array length allowed # # Other patterns, from left to right, match the class or package name as # returned from Class.getName. # If the class is an array type, the class or package to be matched is the # element type. # Arrays of any number of dimensions are treated the same as the element type. # For example, a pattern of "!example.Foo", rejects creation of any instance or # array of example.Foo. # # If the pattern starts with "!", the status is REJECTED if the remaining # pattern is matched; otherwise the status is ALLOWED if the pattern matches. # If the pattern contains "/", the non-empty prefix up to the "/" is the # module name; # if the module name matches the module name of the class then # the remaining pattern is matched with the class name. # If there is no "/", the module name is not compared. # If the pattern ends with ".**" it matches any class in the package and all # subpackages. # If the pattern ends with ".*" it matches any class in the package. # If the pattern ends with "*", it matches any class with the pattern as a # prefix. # If the pattern is equal to the class name, it matches. # Otherwise, the status is UNDECIDED. # #jdk.serialFilter=pattern;pattern # # RMI Registry Serial Filter # # The filter pattern uses the same format as jdk.serialFilter. # This filter can override the builtin filter if additional types need to be # allowed or rejected from the RMI Registry or to decrease limits but not # to increase limits. # If the limits (maxdepth, maxrefs, or maxbytes) are exceeded, the object is rejected. # # Each non-array type is allowed or rejected if it matches one of the patterns, # evaluated from left to right, and is otherwise allowed. Arrays of any # component type, including subarrays and arrays of primitives, are allowed. # # Array construction of any component type, including subarrays and arrays of # primitives, are allowed unless the length is greater than the maxarray limit. # The filter is applied to each array element. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # The built-in filter allows subclasses of allowed classes and # can approximately be represented as the pattern: # #sun.rmi.registry.registryFilter=\ # maxarray=1000000;\ # maxdepth=20;\ # java.lang.String;\ # java.lang.Number;\ # java.lang.reflect.Proxy;\ # java.rmi.Remote;\ # sun.rmi.server.UnicastRef;\ # sun.rmi.server.RMIClientSocketFactory;\ # sun.rmi.server.RMIServerSocketFactory;\ # java.rmi.activation.ActivationID;\ # java.rmi.server.UID # # RMI Distributed Garbage Collector (DGC) Serial Filter # # The filter pattern uses the same format as jdk.serialFilter. # This filter can override the builtin filter if additional types need to be # allowed or rejected from the RMI DGC. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # The builtin DGC filter can approximately be represented as the filter pattern: # #sun.rmi.transport.dgcFilter=\ # java.rmi.server.ObjID;\ # java.rmi.server.UID;\ # java.rmi.dgc.VMID;\ # java.rmi.dgc.Lease;\ # maxdepth=5;maxarray=10000 # CORBA ORBIorTypeCheckRegistryFilter # Type check enhancement for ORB::string_to_object processing # # An IOR type check filter, if configured, is used by an ORB during # an ORB::string_to_object invocation to check the veracity of the type encoded # in the ior string. # # The filter pattern consists of a semi-colon separated list of class names. # The configured list contains the binary class names of the IDL interface types # corresponding to the IDL stub class to be instantiated. # As such, a filter specifies a list of IDL stub classes that will be # allowed by an ORB when an ORB::string_to_object is invoked. # It is used to specify a white list configuration of acceptable # IDL stub types which may be contained in a stringified IOR # parameter passed as input to an ORB::string_to_object method. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # #com.sun.CORBA.ORBIorTypeCheckRegistryFilter=binary_class_name;binary_class_name # # JCEKS Encrypted Key Serial Filter # # This filter, if configured, is used by the JCEKS KeyStore during the # deserialization of the encrypted Key object stored inside a key entry. # If not configured or the filter result is UNDECIDED (i.e. none of the patterns # matches), the filter configured by jdk.serialFilter will be consulted. # # If the system property jceks.key.serialFilter is also specified, it supersedes # the security property value defined here. # # The filter pattern uses the same format as jdk.serialFilter. The default # pattern allows java.lang.Enum, java.security.KeyRep, java.security.KeyRep$Type, # and javax.crypto.spec.SecretKeySpec and rejects all the others. jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep;\ java.base/java.security.KeyRep$Type;java.base/javax.crypto.spec.SecretKeySpec;!* # # Enhanced exception message information # # By default, exception messages should not include potentially sensitive # information such as file names, host names, or port numbers. This property # accepts one or more comma separated values, each of which represents a # category of enhanced exception message information to enable. Values are # case-insensitive. Leading and trailing whitespaces, surrounding each value, # are ignored. Unknown values are ignored. # # NOTE: Use caution before setting this property. Setting this property # exposes sensitive information in Exceptions, which could, for example, # propagate to untrusted code or be emitted in stack traces that are # inadvertently disclosed and made accessible over a public network. # # The categories are: # # hostInfo - IOExceptions thrown by java.net.Socket and the socket types in the # java.nio.channels package will contain enhanced exception # message information # # The property setting in this file can be overridden by a system property of # the same name, with the same syntax and possible values. # #jdk.includeInExceptions=hostInfo # # Policies for distrusting Certificate Authorities (CAs). # # This is a comma separated value of one or more case-sensitive strings, each # of which represents a policy for determining if a CA should be distrusted. # The supported values are: # # SYMANTEC_TLS : Distrust TLS Server certificates anchored by a Symantec # root CA and issued after April 16, 2019 unless issued by one of the # following subordinate CAs which have a later distrust date: # 1. Apple IST CA 2 - G1, SHA-256 fingerprint: # AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B # Distrust after December 31, 2019. # 2. Apple IST CA 8 - G1, SHA-256 fingerprint: # A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED # Distrust after December 31, 2019. # # Leading and trailing whitespace surrounding each value are ignored. # Unknown values are ignored. If the property is commented out or set to the # empty String, no policies are enforced. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be supported by other SE implementations. Also, this # property does not override other security properties which can restrict # certificates such as jdk.tls.disabledAlgorithms or # jdk.certpath.disabledAlgorithms; those restrictions are still enforced even # if this property is not enabled. # jdk.security.caDistrustPolicies=SYMANTEC_TLS OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/jdk21-fips-security000066400000000000000000001277111527232126200301150ustar00rootroot00000000000000# # This is the "master security properties file". # # An alternate java.security properties file may be specified # from the command line via the system property # # -Djava.security.properties= # # This properties file appends to the master security properties file. # If both properties files specify values for the same key, the value # from the command-line properties file is selected, as it is the last # one loaded. # # Also, if you specify # # -Djava.security.properties== (2 equals), # # then that properties file completely overrides the master security # properties file. # # To disable the ability to specify an additional properties file from # the command line, set the key security.overridePropertiesFile # to false in the master security properties file. It is set to true # by default. # In this file, various security properties are set for use by # java.security classes. This is where users can statically register # Cryptography Package Providers ("providers" for short). The term # "provider" refers to a package or set of packages that supply a # concrete implementation of a subset of the cryptography aspects of # the Java Security API. A provider may, for example, implement one or # more digital signature algorithms or message digest algorithms. # # Each provider must implement a subclass of the Provider class. # To register a provider in this master security properties file, # specify the provider and priority in the format # # security.provider.= # # This declares a provider, and specifies its preference # order n. The preference order is the order in which providers are # searched for requested algorithms (when no specific provider is # requested). The order is 1-based; 1 is the most preferred, followed # by 2, and so on. # # must specify the name of the Provider as passed to its super # class java.security.Provider constructor. This is for providers loaded # through the ServiceLoader mechanism. # # must specify the subclass of the Provider class whose # constructor sets the values of various properties that are required # for the Java Security API to look up the algorithms or other # facilities implemented by the provider. This is for providers loaded # through classpath. # # Note: Providers can be dynamically registered instead by calls to # either the addProvider or insertProviderAt method in the Security # class. # # List of providers and their preference orders (see above): # security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider fips:org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.3=SUN security.provider.4=SunRsaSign #security.provider.5=SunEC #security.provider.6=SunJSSE #security.provider.7=SunJCE #security.provider.8=SunJGSS #security.provider.9=SunSASL #security.provider.10=XMLDSig #security.provider.11=SunPCSC #security.provider.12=JdkLDAP #security.provider.13=JdkSASL #security.provider.14=SunPKCS11 # # A list of preferred providers for specific algorithms. These providers will # be searched for matching algorithms before the list of registered providers. # Entries containing errors (parsing, etc) will be ignored. Use the # -Djava.security.debug=jca property to debug these errors. # # The property is a comma-separated list of serviceType.algorithm:provider # entries. The serviceType (example: "MessageDigest") is optional, and if # not specified, the algorithm applies to all service types that support it. # The algorithm is the standard algorithm name or transformation. # Transformations can be specified in their full standard name # (ex: AES/CBC/PKCS5Padding), or as partial matches (ex: AES, AES/CBC). # The provider is the name of the provider. Any provider that does not # also appear in the registered list will be ignored. # # There is a special serviceType for this property only to group a set of # algorithms together. The type is "Group" and is followed by an algorithm # keyword. Groups are to simplify and lessen the entries on the property # line. Current groups are: # Group.SHA2 = SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 # Group.HmacSHA2 = HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512 # Group.SHA2RSA = SHA224withRSA, SHA256withRSA, SHA384withRSA, SHA512withRSA # Group.SHA2DSA = SHA224withDSA, SHA256withDSA, SHA384withDSA, SHA512withDSA # Group.SHA2ECDSA = SHA224withECDSA, SHA256withECDSA, SHA384withECDSA, \ # SHA512withECDSA # Group.SHA3 = SHA3-224, SHA3-256, SHA3-384, SHA3-512 # Group.HmacSHA3 = HmacSHA3-224, HmacSHA3-256, HmacSHA3-384, HmacSHA3-512 # # Example: # jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \ # MessageDigest.SHA-256:SUN, Group.HmacSHA2:SunJCE # #jdk.security.provider.preferred= # # Sun Provider SecureRandom seed source. # # Select the primary source of seed data for the "NativePRNG", "SHA1PRNG" # and "DRBG" SecureRandom implementations in the "Sun" provider. # (Other SecureRandom implementations might also use this property.) # # On Unix-like systems (for example, Solaris/Linux/MacOS), the # "NativePRNG", "SHA1PRNG" and "DRBG" implementations obtains seed data from # special device files such as file:/dev/random. # # On Windows systems, specifying the URLs "file:/dev/random" or # "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding # mechanism for SHA1PRNG and DRBG. # # By default, an attempt is made to use the entropy gathering device # specified by the "securerandom.source" Security property. If an # exception occurs while accessing the specified URL: # # NativePRNG: # a default value of /dev/random will be used. If neither # are available, the implementation will be disabled. # "file" is the only currently supported protocol type. # # SHA1PRNG and DRBG: # the traditional system/thread activity algorithm will be used. # # The entropy gathering device can also be specified with the System # property "java.security.egd". For example: # # % java -Djava.security.egd=file:/dev/random MainClass # # Specifying this System property will override the # "securerandom.source" Security property. # # In addition, if "file:/dev/random" or "file:/dev/urandom" is # specified, the "NativePRNG" implementation will be more preferred than # DRBG and SHA1PRNG in the Sun provider. # securerandom.source=file:/dev/random # # A list of known strong SecureRandom implementations. # # To help guide applications in selecting a suitable strong # java.security.SecureRandom implementation, Java distributions should # indicate a list of known strong implementations using the property. # # This is a comma-separated list of algorithm and/or algorithm:provider # entries. # securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN # # Sun provider DRBG configuration and default instantiation request. # # NIST SP 800-90Ar1 lists several DRBG mechanisms. Each can be configured # with a DRBG algorithm name, and can be instantiated with a security strength, # prediction resistance support, etc. This property defines the configuration # and the default instantiation request of "DRBG" SecureRandom implementations # in the SUN provider. (Other DRBG implementations can also use this property.) # Applications can request different instantiation parameters like security # strength, capability, personalization string using one of the # getInstance(...,SecureRandomParameters,...) methods with a # DrbgParameters.Instantiation argument, but other settings such as the # mechanism and DRBG algorithm names are not currently configurable by any API. # # Please note that the SUN implementation of DRBG always supports reseeding. # # The value of this property is a comma-separated list of all configurable # aspects. The aspects can appear in any order but the same aspect can only # appear at most once. Its BNF-style definition is: # # Value: # aspect { "," aspect } # # aspect: # mech_name | algorithm_name | strength | capability | df # # // The DRBG mechanism to use. Default "Hash_DRBG" # mech_name: # "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG" # # // The DRBG algorithm name. The "SHA-***" names are for Hash_DRBG and # // HMAC_DRBG, default "SHA-256". The "AES-***" names are for CTR_DRBG, # // default "AES-128" when using the limited cryptographic or "AES-256" # // when using the unlimited. # algorithm_name: # "SHA-224" | "SHA-512/224" | "SHA-256" | # "SHA-512/256" | "SHA-384" | "SHA-512" | # "AES-128" | "AES-192" | "AES-256" # # // Security strength requested. Default "128" # strength: # "112" | "128" | "192" | "256" # # // Prediction resistance and reseeding request. Default "none" # // "pr_and_reseed" - Both prediction resistance and reseeding # // support requested # // "reseed_only" - Only reseeding support requested # // "none" - Neither prediction resistance not reseeding # // support requested # pr: # "pr_and_reseed" | "reseed_only" | "none" # # // Whether a derivation function should be used. only applicable # // to CTR_DRBG. Default "use_df" # df: # "use_df" | "no_df" # # Examples, # securerandom.drbg.config=Hash_DRBG,SHA-224,112,none # securerandom.drbg.config=CTR_DRBG,AES-256,192,pr_and_reseed,use_df # # The default value is an empty string, which is equivalent to # securerandom.drbg.config=Hash_DRBG,SHA-256,128,none # securerandom.drbg.config= # # Class to instantiate as the javax.security.auth.login.Configuration # provider. # login.configuration.provider=sun.security.provider.ConfigFile # # Default login configuration file # #login.config.url.1=file:${user.home}/.java.login.config # # Class to instantiate as the system Policy. This is the name of the class # that will be used as the Policy object. The system class loader is used to # locate this class. # policy.provider=sun.security.provider.PolicyFile # The default is to have a single system-wide policy file, # and a policy file in the user's home directory. # policy.url.1=file:${java.home}/conf/security/java.policy policy.url.2=file:${user.home}/.java.policy # whether or not we expand properties in the policy file # if this is set to false, properties (${...}) will not be expanded in policy # files. # policy.expandProperties=true # whether or not we allow an extra policy to be passed on the command line # with -Djava.security.policy=somefile. Comment out this line to disable # this feature. # policy.allowSystemProperty=true # whether or not we look into the IdentityScope for trusted Identities # when encountering a 1.1 signed JAR file. If the identity is found # and is trusted, we grant it AllPermission. Note: the default policy # provider (sun.security.provider.PolicyFile) does not support this property. # policy.ignoreIdentityScope=false # # Default keystore type. # keystore.type=pkcs12 # # Controls compatibility mode for JKS and PKCS12 keystore types. # # When set to 'true', both JKS and PKCS12 keystore types support loading # keystore files in either JKS or PKCS12 format. When set to 'false' the # JKS keystore type supports loading only JKS keystore files and the PKCS12 # keystore type supports loading only PKCS12 keystore files. # keystore.type.compat=true # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when passed to the # SecurityManager::checkPackageAccess method unless the corresponding # RuntimePermission("accessClassInPackage."+package) has been granted. # package.access=sun.misc.,\ sun.reflect.,\ org.GNOME.Accessibility. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when passed to the # SecurityManager::checkPackageDefinition method unless the corresponding # RuntimePermission("defineClassInPackage."+package) has been granted. # # By default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # package.definition=sun.misc.,\ sun.reflect. # # Determines whether this properties file can be appended to # or overridden on the command line via -Djava.security.properties # security.overridePropertiesFile=true # # Determines the default key and trust manager factory algorithms for # the javax.net.ssl package. # ssl.KeyManagerFactory.algorithm=BCFKS ssl.TrustManagerFactory.algorithm=PKIX # # The Java-level namelookup cache policy for successful lookups: # # any negative value: caching forever # any positive value: the number of seconds to cache an address for # zero: do not cache # # default value is forever (FOREVER). For security reasons, this # caching is made forever when a security manager is set. When a security # manager is not set, the default behavior in this implementation # is to cache for 30 seconds. # # NOTE: setting this to anything other than the default value can have # serious security implications. Do not set it unless # you are sure you are not exposed to DNS spoofing attack. # #networkaddress.cache.ttl=-1 # The Java-level namelookup cache policy for failed lookups: # # any negative value: cache forever # any positive value: the number of seconds to cache negative lookup results # zero: do not cache # # In some Microsoft Windows networking environments that employ # the WINS name service in addition to DNS, name service lookups # that fail may take a noticeably long time to return (approx. 5 seconds). # For this reason the default caching policy is to maintain these # results for 10 seconds. # networkaddress.cache.negative.ttl=10 # # Properties to configure OCSP for certificate revocation checking # # Enable OCSP # # By default, OCSP is not used for certificate revocation checking. # This property enables the use of OCSP when set to the value "true". # # NOTE: SocketPermission is required to connect to an OCSP responder. # # Example, # ocsp.enable=true # # Location of the OCSP responder # # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the # Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, # ocsp.responderURL=http://ocsp.example.net:80 # # Subject name of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # distinguished name (defined in RFC 2253) which identifies a certificate in # the set of certificates supplied during cert path validation. In cases where # the subject name alone is not sufficient to uniquely identify the certificate # then both the "ocsp.responderCertIssuerName" and # "ocsp.responderCertSerialNumber" properties must be used instead. When this # property is set then those two properties are ignored. # # Example, # ocsp.responderCertSubjectName=CN=OCSP Responder, O=XYZ Corp # # Issuer name of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # distinguished name (defined in RFC 2253) which identifies a certificate in # the set of certificates supplied during cert path validation. When this # property is set then the "ocsp.responderCertSerialNumber" property must also # be set. When the "ocsp.responderCertSubjectName" property is set then this # property is ignored. # # Example, # ocsp.responderCertIssuerName=CN=Enterprise CA, O=XYZ Corp # # Serial number of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # of hexadecimal digits (colon or space separators may be present) which # identifies a certificate in the set of certificates supplied during cert path # validation. When this property is set then the "ocsp.responderCertIssuerName" # property must also be set. When the "ocsp.responderCertSubjectName" property # is set then this property is ignored. # # Example, # ocsp.responderCertSerialNumber=2A:FF:00 # # Policy for failed Kerberos KDC lookups: # # When a KDC is unavailable (network error, service failure, etc), it is # put inside a blacklist and accessed less often for future requests. The # value (case-insensitive) for this policy can be: # # tryLast # KDCs in the blacklist are always tried after those not on the list. # # tryLess[:max_retries,timeout] # KDCs in the blacklist are still tried by their order in the configuration, # but with smaller max_retries and timeout values. max_retries and timeout # are optional numerical parameters (default 1 and 5000, which means once # and 5 seconds). Please notes that if any of the values defined here is # more than what is defined in krb5.conf, it will be ignored. # # Whenever a KDC is detected as available, it is removed from the blacklist. # The blacklist is reset when krb5.conf is reloaded. You can add # refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is # reloaded whenever a JAAS authentication is attempted. # # Example, # krb5.kdc.bad.policy = tryLast # krb5.kdc.bad.policy = tryLess:2,2000 # krb5.kdc.bad.policy = tryLast # # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable # for certification path building and validation. For example, "MD2" is # generally no longer considered to be a secure hash algorithm. This section # describes the mechanism for disabling algorithms based on algorithm name # and/or key length. This includes algorithms used in certificates, as well # as revocation information such as CRLs and signed OCSP Responses. # The syntax of the disabled algorithm string is described as follows: # DisabledAlgorithms: # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: # AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: # KeySizeConstraint | CAConstraint | DenyAfterConstraint | # UsageConstraint # # KeySizeConstraint: # keySize Operator KeyLength # # Operator: # <= | < | == | != | >= | > # # KeyLength: # Integer value of the algorithm's key length in bits # # CAConstraint: # jdkCA # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # # UsageConstraint: # usage [TLSServer] [TLSClient] [SignedJAR] # # The "AlgorithmName" is the standard algorithm name of the disabled # algorithm. See "Java Cryptography Architecture Standard Algorithm Name # Documentation" for information about Standard Algorithm Names. Matching # is performed using a case-insensitive sub-element matching rule. (For # example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and # "ECDSA" for signatures.) If the assertion "AlgorithmName" is a # sub-element of the certificate algorithm name, the algorithm will be # rejected during certification path building and validation. For example, # the assertion algorithm name "DSA" will disable all certificate algorithms # that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion # will not disable algorithms related to "ECDSA". # # A "Constraint" defines restrictions on the keys and/or certificates for # a specified AlgorithmName: # # KeySizeConstraint: # keySize Operator KeyLength # The constraint requires a key of a valid size range if the # "AlgorithmName" is of a key algorithm. The "KeyLength" indicates # the key size specified in number of bits. For example, # "RSA keySize <= 1024" indicates that any RSA key with key size less # than or equal to 1024 bits should be disabled, and # "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key # with key size less than 1024 or greater than 2048 should be disabled. # This constraint is only used on algorithms that have a key size. # # CAConstraint: # jdkCA # This constraint prohibits the specified algorithm only if the # algorithm is used in a certificate chain that terminates at a marked # trust anchor in the lib/security/cacerts keystore. If the jdkCA # constraint is not set, then all chains using the specified algorithm # are restricted. jdkCA may only be used once in a DisabledAlgorithm # expression. # Example: To apply this constraint to SHA-1 certificates, include # the following: "SHA1 jdkCA" # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # This constraint prohibits a certificate with the specified algorithm # from being used after the date regardless of the certificate's # validity. JAR files that are signed and timestamped before the # constraint date with certificates containing the disabled algorithm # will not be restricted. The date is processed in the UTC timezone. # This constraint can only be used once in a DisabledAlgorithm # expression. # Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020, # use the following: "RSA keySize == 2048 & denyAfter 2020-02-03" # # UsageConstraint: # usage [TLSServer] [TLSClient] [SignedJAR] # This constraint prohibits the specified algorithm for # a specified usage. This should be used when disabling an algorithm # for all usages is not practical. 'TLSServer' restricts the algorithm # in TLS server certificate chains when server authentication is # performed. 'TLSClient' restricts the algorithm in TLS client # certificate chains when client authentication is performed. # 'SignedJAR' constrains use of certificates in signed jar files. # The usage type follows the keyword and more than one usage type can # be specified with a whitespace delimiter. # Example: "SHA1 usage TLSServer TLSClient" # # When an algorithm must satisfy more than one constraint, it must be # delimited by an ampersand '&'. For example, to restrict certificates in a # chain that terminate at a distribution provided trust anchor and contain # RSA keys that are less than or equal to 1024 bits, add the following # constraint: "RSA keySize <= 1024 & jdkCA". # # All DisabledAlgorithms expressions are processed in the order defined in the # property. This requires lower keysize constraints to be specified # before larger keysize constraints of the same algorithm. For example: # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". # # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # # Note: This property is currently used by Oracle's PKIX implementation. It # is not guaranteed to be examined and used by other implementations. # # Example: # jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 # # jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \ RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224 # # Algorithm restrictions for signed JAR files # # In some environments, certain algorithms or key lengths may be undesirable # for signed JAR validation. For example, "MD2" is generally no longer # considered to be a secure hash algorithm. This section describes the # mechanism for disabling algorithms based on algorithm name and/or key length. # JARs signed with any of the disabled algorithms or key sizes will be treated # as unsigned. # # The syntax of the disabled algorithm string is described as follows: # DisabledAlgorithms: # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: # AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: # KeySizeConstraint | DenyAfterConstraint # # KeySizeConstraint: # keySize Operator KeyLength # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # # Operator: # <= | < | == | != | >= | > # # KeyLength: # Integer value of the algorithm's key length in bits # # Note: This property is currently used by the JDK Reference # implementation. It is not guaranteed to be examined and used by other # implementations. # # See "jdk.certpath.disabledAlgorithms" for syntax descriptions. # jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ DSA keySize < 1024 # # Algorithm restrictions for Secure Socket Layer/Transport Layer Security # (SSL/TLS/DTLS) processing # # In some environments, certain algorithms or key lengths may be undesirable # when using SSL/TLS/DTLS. This section describes the mechanism for disabling # algorithms during SSL/TLS/DTLS security parameters negotiation, including # protocol version negotiation, cipher suites selection, peer authentication # and key exchange mechanisms. # # Disabled algorithms will not be negotiated for SSL/TLS connections, even # if they are enabled explicitly in an application. # # For PKI-based peer authentication and key exchange mechanisms, this list # of disabled algorithms will also be checked during certification path # building and validation, including algorithms used in certificates, as # well as revocation information such as CRLs and signed OCSP Responses. # This is in addition to the jdk.certpath.disabledAlgorithms property above. # # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ EC keySize < 224, 3DES_EDE_CBC, anon, NULL # # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) # processing in JSSE implementation. # # In some environments, a certain algorithm may be undesirable but it # cannot be disabled because of its use in legacy applications. Legacy # algorithms may still be supported, but applications should not use them # as the security strength of legacy algorithms are usually not strong enough # in practice. # # During SSL/TLS security parameters negotiation, legacy algorithms will # not be negotiated unless there are no other candidates. # # The syntax of the legacy algorithms string is described as this Java # BNF-style: # LegacyAlgorithms: # " LegacyAlgorithm { , LegacyAlgorithm } " # # LegacyAlgorithm: # AlgorithmName (standard JSSE algorithm name) # # See the specification of security property "jdk.certpath.disabledAlgorithms" # for the syntax and description of the "AlgorithmName" notation. # # Per SSL/TLS specifications, cipher suites have the form: # SSL_KeyExchangeAlg_WITH_CipherAlg_MacAlg # or # TLS_KeyExchangeAlg_WITH_CipherAlg_MacAlg # # For example, the cipher suite TLS_RSA_WITH_AES_128_CBC_SHA uses RSA as the # key exchange algorithm, AES_128_CBC (128 bits AES cipher algorithm in CBC # mode) as the cipher (encryption) algorithm, and SHA-1 as the message digest # algorithm for HMAC. # # The LegacyAlgorithm can be one of the following standard algorithm names: # 1. JSSE cipher suite name, e.g., TLS_RSA_WITH_AES_128_CBC_SHA # 2. JSSE key exchange algorithm name, e.g., RSA # 3. JSSE cipher (encryption) algorithm name, e.g., AES_128_CBC # 4. JSSE message digest algorithm name, e.g., SHA # # See SSL/TLS specifications and "Java Cryptography Architecture Standard # Algorithm Name Documentation" for information about the algorithm names. # # Note: If a legacy algorithm is also restricted through the # jdk.tls.disabledAlgorithms property or the # java.security.AlgorithmConstraints API (See # javax.net.ssl.SSLParameters.setAlgorithmConstraints()), # then the algorithm is completely disabled and will not be negotiated. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # There is no guarantee the property will continue to exist or be of the # same syntax in future releases. # # Example: # jdk.tls.legacyAlgorithms=DH_anon, DES_CBC, SSL_RSA_WITH_RC4_128_MD5 # jdk.tls.legacyAlgorithms= \ K_NULL, C_NULL, M_NULL, \ DH_anon, ECDH_anon, \ RC4_128, RC4_40, DES_CBC, DES40_CBC, \ 3DES_EDE_CBC # # The pre-defined default finite field Diffie-Hellman ephemeral (DHE) # parameters for Transport Layer Security (SSL/TLS/DTLS) processing. # # In traditional SSL/TLS/DTLS connections where finite field DHE parameters # negotiation mechanism is not used, the server offers the client group # parameters, base generator g and prime modulus p, for DHE key exchange. # It is recommended to use dynamic group parameters. This property defines # a mechanism that allows you to specify custom group parameters. # # The syntax of this property string is described as this Java BNF-style: # DefaultDHEParameters: # DefinedDHEParameters { , DefinedDHEParameters } # # DefinedDHEParameters: # "{" DHEPrimeModulus , DHEBaseGenerator "}" # # DHEPrimeModulus: # HexadecimalDigits # # DHEBaseGenerator: # HexadecimalDigits # # HexadecimalDigits: # HexadecimalDigit { HexadecimalDigit } # # HexadecimalDigit: one of # 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f # # Whitespace characters are ignored. # # The "DefinedDHEParameters" defines the custom group parameters, prime # modulus p and base generator g, for a particular size of prime modulus p. # The "DHEPrimeModulus" defines the hexadecimal prime modulus p, and the # "DHEBaseGenerator" defines the hexadecimal base generator g of a group # parameter. It is recommended to use safe primes for the custom group # parameters. # # If this property is not defined or the value is empty, the underlying JSSE # provider's default group parameter is used for each connection. # # If the property value does not follow the grammar, or a particular group # parameter is not valid, the connection will fall back and use the # underlying JSSE provider's default group parameter. # # Note: This property is currently used by OpenJDK's JSSE implementation. It # is not guaranteed to be examined and used by other implementations. # # Example: # jdk.tls.server.defaultDHEParameters= # { \ # FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 \ # 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD \ # EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 \ # E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED \ # EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 \ # FFFFFFFF FFFFFFFF, 2} # # TLS key limits on symmetric cryptographic algorithms # # This security property sets limits on algorithms key usage in TLS 1.3. # When the amount of data encrypted exceeds the algorithm value listed below, # a KeyUpdate message will trigger a key change. This is for symmetric ciphers # with TLS 1.3 only. # # The syntax for the property is described below: # KeyLimits: # " KeyLimit { , KeyLimit } " # # WeakKeyLimit: # AlgorithmName Action Length # # AlgorithmName: # A full algorithm transformation. # # Action: # KeyUpdate # # Length: # The amount of encrypted data in a session before the Action occurs # This value may be an integer value in bytes, or as a power of two, 2^29. # # KeyUpdate: # The TLS 1.3 KeyUpdate handshake process begins when the Length amount # is fulfilled. # # Note: This property is currently used by OpenJDK's JSSE implementation. It # is not guaranteed to be examined and used by other implementations. # jdk.tls.keyLimits=AES/GCM/NoPadding KeyUpdate 2^37 # # Cryptographic Jurisdiction Policy defaults # # Import and export control rules on cryptographic software vary from # country to country. By default, Java provides two different sets of # cryptographic policy files[1]: # # unlimited: These policy files contain no restrictions on cryptographic # strengths or algorithms # # limited: These policy files contain more restricted cryptographic # strengths # # The default setting is determined by the value of the "crypto.policy" # Security property below. If your country or usage requires the # traditional restrictive policy, the "limited" Java cryptographic # policy is still available and may be appropriate for your environment. # # If you have restrictions that do not fit either use case mentioned # above, Java provides the capability to customize these policy files. # The "crypto.policy" security property points to a subdirectory # within /conf/security/policy/ which can be customized. # Please see the /conf/security/policy/README.txt file or consult # the Java Security Guide/JCA documentation for more information. # # YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY # TO DETERMINE THE EXACT REQUIREMENTS. # # [1] Please note that the JCE for Java SE, including the JCE framework, # cryptographic policy files, and standard JCE providers provided with # the Java SE, have been reviewed and approved for export as mass market # encryption item by the US Bureau of Industry and Security. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # crypto.policy=unlimited # # The policy for the XML Signature secure validation mode. The mode is # enabled by setting the property "org.jcp.xml.dsig.secureValidation" to # true with the javax.xml.crypto.XMLCryptoContext.setProperty() method, # or by running the code with a SecurityManager. # # Policy: # Constraint {"," Constraint } # Constraint: # AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint | # ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint # AlgConstraint # "disallowAlg" Uri # MaxTransformsConstraint: # "maxTransforms" Integer # MaxReferencesConstraint: # "maxReferences" Integer # ReferenceUriSchemeConstraint: # "disallowReferenceUriSchemes" String { String } # KeySizeConstraint: # "minKeySize" KeyAlg Integer # OtherConstraint: # "noDuplicateIds" | "noRetrievalMethodLoops" # # For AlgConstraint, Uri is the algorithm URI String that is not allowed. # See the XML Signature Recommendation for more information on algorithm # URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm # name of the key type (ex: "RSA"). If the MaxTransformsConstraint, # MaxReferencesConstraint or KeySizeConstraint (for the same key type) is # specified more than once, only the last entry is enforced. # # Note: This property is currently used by the JDK Reference implementation. It # is not guaranteed to be examined and used by other implementations. # jdk.xml.dsig.secureValidationPolicy=\ disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,\ maxTransforms 5,\ maxReferences 30,\ disallowReferenceUriSchemes file http https,\ minKeySize RSA 1024,\ minKeySize DSA 1024,\ minKeySize EC 224,\ noDuplicateIds,\ noRetrievalMethodLoops # # Serialization process-wide filter # # A filter, if configured, is used by java.io.ObjectInputStream during # deserialization to check the contents of the stream. # A filter is configured as a sequence of patterns, each pattern is either # matched against the name of a class in the stream or defines a limit. # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # # If the system property jdk.serialFilter is also specified, it supersedes # the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. # Limits are checked before classes regardless of the order in the # sequence of patterns. # If any of the limits are exceeded, the filter status is REJECTED. # # maxdepth=value - the maximum depth of a graph # maxrefs=value - the maximum number of internal references # maxbytes=value - the maximum number of bytes in the input stream # maxarray=value - the maximum array length allowed # # Other patterns, from left to right, match the class or package name as # returned from Class.getName. # If the class is an array type, the class or package to be matched is the # element type. # Arrays of any number of dimensions are treated the same as the element type. # For example, a pattern of "!example.Foo", rejects creation of any instance or # array of example.Foo. # # If the pattern starts with "!", the status is REJECTED if the remaining # pattern is matched; otherwise the status is ALLOWED if the pattern matches. # If the pattern contains "/", the non-empty prefix up to the "/" is the # module name; # if the module name matches the module name of the class then # the remaining pattern is matched with the class name. # If there is no "/", the module name is not compared. # If the pattern ends with ".**" it matches any class in the package and all # subpackages. # If the pattern ends with ".*" it matches any class in the package. # If the pattern ends with "*", it matches any class with the pattern as a # prefix. # If the pattern is equal to the class name, it matches. # Otherwise, the status is UNDECIDED. # #jdk.serialFilter=pattern;pattern # # RMI Registry Serial Filter # # The filter pattern uses the same format as jdk.serialFilter. # This filter can override the builtin filter if additional types need to be # allowed or rejected from the RMI Registry or to decrease limits but not # to increase limits. # If the limits (maxdepth, maxrefs, or maxbytes) are exceeded, the object is rejected. # # Each non-array type is allowed or rejected if it matches one of the patterns, # evaluated from left to right, and is otherwise allowed. Arrays of any # component type, including subarrays and arrays of primitives, are allowed. # # Array construction of any component type, including subarrays and arrays of # primitives, are allowed unless the length is greater than the maxarray limit. # The filter is applied to each array element. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # The built-in filter allows subclasses of allowed classes and # can approximately be represented as the pattern: # #sun.rmi.registry.registryFilter=\ # maxarray=1000000;\ # maxdepth=20;\ # java.lang.String;\ # java.lang.Number;\ # java.lang.reflect.Proxy;\ # java.rmi.Remote;\ # sun.rmi.server.UnicastRef;\ # sun.rmi.server.RMIClientSocketFactory;\ # sun.rmi.server.RMIServerSocketFactory;\ # java.rmi.activation.ActivationID;\ # java.rmi.server.UID # # RMI Distributed Garbage Collector (DGC) Serial Filter # # The filter pattern uses the same format as jdk.serialFilter. # This filter can override the builtin filter if additional types need to be # allowed or rejected from the RMI DGC. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # The builtin DGC filter can approximately be represented as the filter pattern: # #sun.rmi.transport.dgcFilter=\ # java.rmi.server.ObjID;\ # java.rmi.server.UID;\ # java.rmi.dgc.VMID;\ # java.rmi.dgc.Lease;\ # maxdepth=5;maxarray=10000 # CORBA ORBIorTypeCheckRegistryFilter # Type check enhancement for ORB::string_to_object processing # # An IOR type check filter, if configured, is used by an ORB during # an ORB::string_to_object invocation to check the veracity of the type encoded # in the ior string. # # The filter pattern consists of a semi-colon separated list of class names. # The configured list contains the binary class names of the IDL interface types # corresponding to the IDL stub class to be instantiated. # As such, a filter specifies a list of IDL stub classes that will be # allowed by an ORB when an ORB::string_to_object is invoked. # It is used to specify a white list configuration of acceptable # IDL stub types which may be contained in a stringified IOR # parameter passed as input to an ORB::string_to_object method. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # #com.sun.CORBA.ORBIorTypeCheckRegistryFilter=binary_class_name;binary_class_name # # JCEKS Encrypted Key Serial Filter # # This filter, if configured, is used by the JCEKS KeyStore during the # deserialization of the encrypted Key object stored inside a key entry. # If not configured or the filter result is UNDECIDED (i.e. none of the patterns # matches), the filter configured by jdk.serialFilter will be consulted. # # If the system property jceks.key.serialFilter is also specified, it supersedes # the security property value defined here. # # The filter pattern uses the same format as jdk.serialFilter. The default # pattern allows java.lang.Enum, java.security.KeyRep, java.security.KeyRep$Type, # and javax.crypto.spec.SecretKeySpec and rejects all the others. jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep;\ java.base/java.security.KeyRep$Type;java.base/javax.crypto.spec.SecretKeySpec;!* # # Enhanced exception message information # # By default, exception messages should not include potentially sensitive # information such as file names, host names, or port numbers. This property # accepts one or more comma separated values, each of which represents a # category of enhanced exception message information to enable. Values are # case-insensitive. Leading and trailing whitespaces, surrounding each value, # are ignored. Unknown values are ignored. # # NOTE: Use caution before setting this property. Setting this property # exposes sensitive information in Exceptions, which could, for example, # propagate to untrusted code or be emitted in stack traces that are # inadvertently disclosed and made accessible over a public network. # # The categories are: # # hostInfo - IOExceptions thrown by java.net.Socket and the socket types in the # java.nio.channels package will contain enhanced exception # message information # # The property setting in this file can be overridden by a system property of # the same name, with the same syntax and possible values. # #jdk.includeInExceptions=hostInfo # # Policies for distrusting Certificate Authorities (CAs). # # This is a comma separated value of one or more case-sensitive strings, each # of which represents a policy for determining if a CA should be distrusted. # The supported values are: # # SYMANTEC_TLS : Distrust TLS Server certificates anchored by a Symantec # root CA and issued after April 16, 2019 unless issued by one of the # following subordinate CAs which have a later distrust date: # 1. Apple IST CA 2 - G1, SHA-256 fingerprint: # AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B # Distrust after December 31, 2019. # 2. Apple IST CA 8 - G1, SHA-256 fingerprint: # A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED # Distrust after December 31, 2019. # # Leading and trailing whitespace surrounding each value are ignored. # Unknown values are ignored. If the property is commented out or set to the # empty String, no policies are enforced. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be supported by other SE implementations. Also, this # property does not override other security properties which can restrict # certificates such as jdk.tls.disabledAlgorithms or # jdk.certpath.disabledAlgorithms; those restrictions are still enforced even # if this property is not enabled. # jdk.security.caDistrustPolicies=SYMANTEC_TLS OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/jdk25-fips-security000066400000000000000000001277111527232126200301210ustar00rootroot00000000000000# # This is the "master security properties file". # # An alternate java.security properties file may be specified # from the command line via the system property # # -Djava.security.properties= # # This properties file appends to the master security properties file. # If both properties files specify values for the same key, the value # from the command-line properties file is selected, as it is the last # one loaded. # # Also, if you specify # # -Djava.security.properties== (2 equals), # # then that properties file completely overrides the master security # properties file. # # To disable the ability to specify an additional properties file from # the command line, set the key security.overridePropertiesFile # to false in the master security properties file. It is set to true # by default. # In this file, various security properties are set for use by # java.security classes. This is where users can statically register # Cryptography Package Providers ("providers" for short). The term # "provider" refers to a package or set of packages that supply a # concrete implementation of a subset of the cryptography aspects of # the Java Security API. A provider may, for example, implement one or # more digital signature algorithms or message digest algorithms. # # Each provider must implement a subclass of the Provider class. # To register a provider in this master security properties file, # specify the provider and priority in the format # # security.provider.= # # This declares a provider, and specifies its preference # order n. The preference order is the order in which providers are # searched for requested algorithms (when no specific provider is # requested). The order is 1-based; 1 is the most preferred, followed # by 2, and so on. # # must specify the name of the Provider as passed to its super # class java.security.Provider constructor. This is for providers loaded # through the ServiceLoader mechanism. # # must specify the subclass of the Provider class whose # constructor sets the values of various properties that are required # for the Java Security API to look up the algorithms or other # facilities implemented by the provider. This is for providers loaded # through classpath. # # Note: Providers can be dynamically registered instead by calls to # either the addProvider or insertProviderAt method in the Security # class. # # List of providers and their preference orders (see above): # security.provider.1=org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.2=org.bouncycastle.jsse.provider.BouncyCastleJsseProvider fips:org.bouncycastle.jcajce.provider.BouncyCastleFipsProvider security.provider.3=SUN security.provider.4=SunRsaSign #security.provider.5=SunEC #security.provider.6=SunJSSE #security.provider.7=SunJCE #security.provider.8=SunJGSS #security.provider.9=SunSASL #security.provider.10=XMLDSig #security.provider.11=SunPCSC #security.provider.12=JdkLDAP #security.provider.13=JdkSASL #security.provider.14=SunPKCS11 # # A list of preferred providers for specific algorithms. These providers will # be searched for matching algorithms before the list of registered providers. # Entries containing errors (parsing, etc) will be ignored. Use the # -Djava.security.debug=jca property to debug these errors. # # The property is a comma-separated list of serviceType.algorithm:provider # entries. The serviceType (example: "MessageDigest") is optional, and if # not specified, the algorithm applies to all service types that support it. # The algorithm is the standard algorithm name or transformation. # Transformations can be specified in their full standard name # (ex: AES/CBC/PKCS5Padding), or as partial matches (ex: AES, AES/CBC). # The provider is the name of the provider. Any provider that does not # also appear in the registered list will be ignored. # # There is a special serviceType for this property only to group a set of # algorithms together. The type is "Group" and is followed by an algorithm # keyword. Groups are to simplify and lessen the entries on the property # line. Current groups are: # Group.SHA2 = SHA-224, SHA-256, SHA-384, SHA-512, SHA-512/224, SHA-512/256 # Group.HmacSHA2 = HmacSHA224, HmacSHA256, HmacSHA384, HmacSHA512 # Group.SHA2RSA = SHA224withRSA, SHA256withRSA, SHA384withRSA, SHA512withRSA # Group.SHA2DSA = SHA224withDSA, SHA256withDSA, SHA384withDSA, SHA512withDSA # Group.SHA2ECDSA = SHA224withECDSA, SHA256withECDSA, SHA384withECDSA, \ # SHA512withECDSA # Group.SHA3 = SHA3-224, SHA3-256, SHA3-384, SHA3-512 # Group.HmacSHA3 = HmacSHA3-224, HmacSHA3-256, HmacSHA3-384, HmacSHA3-512 # # Example: # jdk.security.provider.preferred=AES/GCM/NoPadding:SunJCE, \ # MessageDigest.SHA-256:SUN, Group.HmacSHA2:SunJCE # #jdk.security.provider.preferred= # # Sun Provider SecureRandom seed source. # # Select the primary source of seed data for the "NativePRNG", "SHA1PRNG" # and "DRBG" SecureRandom implementations in the "Sun" provider. # (Other SecureRandom implementations might also use this property.) # # On Unix-like systems (for example, Solaris/Linux/MacOS), the # "NativePRNG", "SHA1PRNG" and "DRBG" implementations obtains seed data from # special device files such as file:/dev/random. # # On Windows systems, specifying the URLs "file:/dev/random" or # "file:/dev/urandom" will enable the native Microsoft CryptoAPI seeding # mechanism for SHA1PRNG and DRBG. # # By default, an attempt is made to use the entropy gathering device # specified by the "securerandom.source" Security property. If an # exception occurs while accessing the specified URL: # # NativePRNG: # a default value of /dev/random will be used. If neither # are available, the implementation will be disabled. # "file" is the only currently supported protocol type. # # SHA1PRNG and DRBG: # the traditional system/thread activity algorithm will be used. # # The entropy gathering device can also be specified with the System # property "java.security.egd". For example: # # % java -Djava.security.egd=file:/dev/random MainClass # # Specifying this System property will override the # "securerandom.source" Security property. # # In addition, if "file:/dev/random" or "file:/dev/urandom" is # specified, the "NativePRNG" implementation will be more preferred than # DRBG and SHA1PRNG in the Sun provider. # securerandom.source=file:/dev/random # # A list of known strong SecureRandom implementations. # # To help guide applications in selecting a suitable strong # java.security.SecureRandom implementation, Java distributions should # indicate a list of known strong implementations using the property. # # This is a comma-separated list of algorithm and/or algorithm:provider # entries. # securerandom.strongAlgorithms=NativePRNGBlocking:SUN,DRBG:SUN # # Sun provider DRBG configuration and default instantiation request. # # NIST SP 800-90Ar1 lists several DRBG mechanisms. Each can be configured # with a DRBG algorithm name, and can be instantiated with a security strength, # prediction resistance support, etc. This property defines the configuration # and the default instantiation request of "DRBG" SecureRandom implementations # in the SUN provider. (Other DRBG implementations can also use this property.) # Applications can request different instantiation parameters like security # strength, capability, personalization string using one of the # getInstance(...,SecureRandomParameters,...) methods with a # DrbgParameters.Instantiation argument, but other settings such as the # mechanism and DRBG algorithm names are not currently configurable by any API. # # Please note that the SUN implementation of DRBG always supports reseeding. # # The value of this property is a comma-separated list of all configurable # aspects. The aspects can appear in any order but the same aspect can only # appear at most once. Its BNF-style definition is: # # Value: # aspect { "," aspect } # # aspect: # mech_name | algorithm_name | strength | capability | df # # // The DRBG mechanism to use. Default "Hash_DRBG" # mech_name: # "Hash_DRBG" | "HMAC_DRBG" | "CTR_DRBG" # # // The DRBG algorithm name. The "SHA-***" names are for Hash_DRBG and # // HMAC_DRBG, default "SHA-256". The "AES-***" names are for CTR_DRBG, # // default "AES-128" when using the limited cryptographic or "AES-256" # // when using the unlimited. # algorithm_name: # "SHA-224" | "SHA-512/224" | "SHA-256" | # "SHA-512/256" | "SHA-384" | "SHA-512" | # "AES-128" | "AES-192" | "AES-256" # # // Security strength requested. Default "128" # strength: # "112" | "128" | "192" | "256" # # // Prediction resistance and reseeding request. Default "none" # // "pr_and_reseed" - Both prediction resistance and reseeding # // support requested # // "reseed_only" - Only reseeding support requested # // "none" - Neither prediction resistance not reseeding # // support requested # pr: # "pr_and_reseed" | "reseed_only" | "none" # # // Whether a derivation function should be used. only applicable # // to CTR_DRBG. Default "use_df" # df: # "use_df" | "no_df" # # Examples, # securerandom.drbg.config=Hash_DRBG,SHA-224,112,none # securerandom.drbg.config=CTR_DRBG,AES-256,192,pr_and_reseed,use_df # # The default value is an empty string, which is equivalent to # securerandom.drbg.config=Hash_DRBG,SHA-256,128,none # securerandom.drbg.config= # # Class to instantiate as the javax.security.auth.login.Configuration # provider. # login.configuration.provider=sun.security.provider.ConfigFile # # Default login configuration file # #login.config.url.1=file:${user.home}/.java.login.config # # Class to instantiate as the system Policy. This is the name of the class # that will be used as the Policy object. The system class loader is used to # locate this class. # policy.provider=sun.security.provider.PolicyFile # The default is to have a single system-wide policy file, # and a policy file in the user's home directory. # policy.url.1=file:${java.home}/conf/security/java.policy policy.url.2=file:${user.home}/.java.policy # whether or not we expand properties in the policy file # if this is set to false, properties (${...}) will not be expanded in policy # files. # policy.expandProperties=true # whether or not we allow an extra policy to be passed on the command line # with -Djava.security.policy=somefile. Comment out this line to disable # this feature. # policy.allowSystemProperty=true # whether or not we look into the IdentityScope for trusted Identities # when encountering a 1.1 signed JAR file. If the identity is found # and is trusted, we grant it AllPermission. Note: the default policy # provider (sun.security.provider.PolicyFile) does not support this property. # policy.ignoreIdentityScope=false # # Default keystore type. # keystore.type=pkcs12 # # Controls compatibility mode for JKS and PKCS12 keystore types. # # When set to 'true', both JKS and PKCS12 keystore types support loading # keystore files in either JKS or PKCS12 format. When set to 'false' the # JKS keystore type supports loading only JKS keystore files and the PKCS12 # keystore type supports loading only PKCS12 keystore files. # keystore.type.compat=true # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when passed to the # SecurityManager::checkPackageAccess method unless the corresponding # RuntimePermission("accessClassInPackage."+package) has been granted. # package.access=sun.misc.,\ sun.reflect.,\ org.GNOME.Accessibility. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when passed to the # SecurityManager::checkPackageDefinition method unless the corresponding # RuntimePermission("defineClassInPackage."+package) has been granted. # # By default, none of the class loaders supplied with the JDK call # checkPackageDefinition. # package.definition=sun.misc.,\ sun.reflect. # # Determines whether this properties file can be appended to # or overridden on the command line via -Djava.security.properties # security.overridePropertiesFile=true # # Determines the default key and trust manager factory algorithms for # the javax.net.ssl package. # ssl.KeyManagerFactory.algorithm=BCFKS ssl.TrustManagerFactory.algorithm=PKIX # # The Java-level namelookup cache policy for successful lookups: # # any negative value: caching forever # any positive value: the number of seconds to cache an address for # zero: do not cache # # default value is forever (FOREVER). For security reasons, this # caching is made forever when a security manager is set. When a security # manager is not set, the default behavior in this implementation # is to cache for 30 seconds. # # NOTE: setting this to anything other than the default value can have # serious security implications. Do not set it unless # you are sure you are not exposed to DNS spoofing attack. # #networkaddress.cache.ttl=-1 # The Java-level namelookup cache policy for failed lookups: # # any negative value: cache forever # any positive value: the number of seconds to cache negative lookup results # zero: do not cache # # In some Microsoft Windows networking environments that employ # the WINS name service in addition to DNS, name service lookups # that fail may take a noticeably long time to return (approx. 5 seconds). # For this reason the default caching policy is to maintain these # results for 10 seconds. # networkaddress.cache.negative.ttl=10 # # Properties to configure OCSP for certificate revocation checking # # Enable OCSP # # By default, OCSP is not used for certificate revocation checking. # This property enables the use of OCSP when set to the value "true". # # NOTE: SocketPermission is required to connect to an OCSP responder. # # Example, # ocsp.enable=true # # Location of the OCSP responder # # By default, the location of the OCSP responder is determined implicitly # from the certificate being validated. This property explicitly specifies # the location of the OCSP responder. The property is used when the # Authority Information Access extension (defined in RFC 5280) is absent # from the certificate or when it requires overriding. # # Example, # ocsp.responderURL=http://ocsp.example.net:80 # # Subject name of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # distinguished name (defined in RFC 2253) which identifies a certificate in # the set of certificates supplied during cert path validation. In cases where # the subject name alone is not sufficient to uniquely identify the certificate # then both the "ocsp.responderCertIssuerName" and # "ocsp.responderCertSerialNumber" properties must be used instead. When this # property is set then those two properties are ignored. # # Example, # ocsp.responderCertSubjectName=CN=OCSP Responder, O=XYZ Corp # # Issuer name of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # distinguished name (defined in RFC 2253) which identifies a certificate in # the set of certificates supplied during cert path validation. When this # property is set then the "ocsp.responderCertSerialNumber" property must also # be set. When the "ocsp.responderCertSubjectName" property is set then this # property is ignored. # # Example, # ocsp.responderCertIssuerName=CN=Enterprise CA, O=XYZ Corp # # Serial number of the OCSP responder's certificate # # By default, the certificate of the OCSP responder is that of the issuer # of the certificate being validated. This property identifies the certificate # of the OCSP responder when the default does not apply. Its value is a string # of hexadecimal digits (colon or space separators may be present) which # identifies a certificate in the set of certificates supplied during cert path # validation. When this property is set then the "ocsp.responderCertIssuerName" # property must also be set. When the "ocsp.responderCertSubjectName" property # is set then this property is ignored. # # Example, # ocsp.responderCertSerialNumber=2A:FF:00 # # Policy for failed Kerberos KDC lookups: # # When a KDC is unavailable (network error, service failure, etc), it is # put inside a blacklist and accessed less often for future requests. The # value (case-insensitive) for this policy can be: # # tryLast # KDCs in the blacklist are always tried after those not on the list. # # tryLess[:max_retries,timeout] # KDCs in the blacklist are still tried by their order in the configuration, # but with smaller max_retries and timeout values. max_retries and timeout # are optional numerical parameters (default 1 and 5000, which means once # and 5 seconds). Please notes that if any of the values defined here is # more than what is defined in krb5.conf, it will be ignored. # # Whenever a KDC is detected as available, it is removed from the blacklist. # The blacklist is reset when krb5.conf is reloaded. You can add # refreshKrb5Config=true to a JAAS configuration file so that krb5.conf is # reloaded whenever a JAAS authentication is attempted. # # Example, # krb5.kdc.bad.policy = tryLast # krb5.kdc.bad.policy = tryLess:2,2000 # krb5.kdc.bad.policy = tryLast # # Algorithm restrictions for certification path (CertPath) processing # # In some environments, certain algorithms or key lengths may be undesirable # for certification path building and validation. For example, "MD2" is # generally no longer considered to be a secure hash algorithm. This section # describes the mechanism for disabling algorithms based on algorithm name # and/or key length. This includes algorithms used in certificates, as well # as revocation information such as CRLs and signed OCSP Responses. # The syntax of the disabled algorithm string is described as follows: # DisabledAlgorithms: # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: # AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: # KeySizeConstraint | CAConstraint | DenyAfterConstraint | # UsageConstraint # # KeySizeConstraint: # keySize Operator KeyLength # # Operator: # <= | < | == | != | >= | > # # KeyLength: # Integer value of the algorithm's key length in bits # # CAConstraint: # jdkCA # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # # UsageConstraint: # usage [TLSServer] [TLSClient] [SignedJAR] # # The "AlgorithmName" is the standard algorithm name of the disabled # algorithm. See "Java Cryptography Architecture Standard Algorithm Name # Documentation" for information about Standard Algorithm Names. Matching # is performed using a case-insensitive sub-element matching rule. (For # example, in "SHA1withECDSA" the sub-elements are "SHA1" for hashing and # "ECDSA" for signatures.) If the assertion "AlgorithmName" is a # sub-element of the certificate algorithm name, the algorithm will be # rejected during certification path building and validation. For example, # the assertion algorithm name "DSA" will disable all certificate algorithms # that rely on DSA, such as NONEwithDSA, SHA1withDSA. However, the assertion # will not disable algorithms related to "ECDSA". # # A "Constraint" defines restrictions on the keys and/or certificates for # a specified AlgorithmName: # # KeySizeConstraint: # keySize Operator KeyLength # The constraint requires a key of a valid size range if the # "AlgorithmName" is of a key algorithm. The "KeyLength" indicates # the key size specified in number of bits. For example, # "RSA keySize <= 1024" indicates that any RSA key with key size less # than or equal to 1024 bits should be disabled, and # "RSA keySize < 1024, RSA keySize > 2048" indicates that any RSA key # with key size less than 1024 or greater than 2048 should be disabled. # This constraint is only used on algorithms that have a key size. # # CAConstraint: # jdkCA # This constraint prohibits the specified algorithm only if the # algorithm is used in a certificate chain that terminates at a marked # trust anchor in the lib/security/cacerts keystore. If the jdkCA # constraint is not set, then all chains using the specified algorithm # are restricted. jdkCA may only be used once in a DisabledAlgorithm # expression. # Example: To apply this constraint to SHA-1 certificates, include # the following: "SHA1 jdkCA" # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # This constraint prohibits a certificate with the specified algorithm # from being used after the date regardless of the certificate's # validity. JAR files that are signed and timestamped before the # constraint date with certificates containing the disabled algorithm # will not be restricted. The date is processed in the UTC timezone. # This constraint can only be used once in a DisabledAlgorithm # expression. # Example: To deny usage of RSA 2048 bit certificates after Feb 3 2020, # use the following: "RSA keySize == 2048 & denyAfter 2020-02-03" # # UsageConstraint: # usage [TLSServer] [TLSClient] [SignedJAR] # This constraint prohibits the specified algorithm for # a specified usage. This should be used when disabling an algorithm # for all usages is not practical. 'TLSServer' restricts the algorithm # in TLS server certificate chains when server authentication is # performed. 'TLSClient' restricts the algorithm in TLS client # certificate chains when client authentication is performed. # 'SignedJAR' constrains use of certificates in signed jar files. # The usage type follows the keyword and more than one usage type can # be specified with a whitespace delimiter. # Example: "SHA1 usage TLSServer TLSClient" # # When an algorithm must satisfy more than one constraint, it must be # delimited by an ampersand '&'. For example, to restrict certificates in a # chain that terminate at a distribution provided trust anchor and contain # RSA keys that are less than or equal to 1024 bits, add the following # constraint: "RSA keySize <= 1024 & jdkCA". # # All DisabledAlgorithms expressions are processed in the order defined in the # property. This requires lower keysize constraints to be specified # before larger keysize constraints of the same algorithm. For example: # "RSA keySize < 1024 & jdkCA, RSA keySize < 2048". # # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # # Note: This property is currently used by Oracle's PKIX implementation. It # is not guaranteed to be examined and used by other implementations. # # Example: # jdk.certpath.disabledAlgorithms=MD2, DSA, RSA keySize < 2048 # # jdk.certpath.disabledAlgorithms=MD2, MD5, SHA1 jdkCA & usage TLSServer, \ RSA keySize < 1024, DSA keySize < 1024, EC keySize < 224 # # Algorithm restrictions for signed JAR files # # In some environments, certain algorithms or key lengths may be undesirable # for signed JAR validation. For example, "MD2" is generally no longer # considered to be a secure hash algorithm. This section describes the # mechanism for disabling algorithms based on algorithm name and/or key length. # JARs signed with any of the disabled algorithms or key sizes will be treated # as unsigned. # # The syntax of the disabled algorithm string is described as follows: # DisabledAlgorithms: # " DisabledAlgorithm { , DisabledAlgorithm } " # # DisabledAlgorithm: # AlgorithmName [Constraint] { '&' Constraint } # # AlgorithmName: # (see below) # # Constraint: # KeySizeConstraint | DenyAfterConstraint # # KeySizeConstraint: # keySize Operator KeyLength # # DenyAfterConstraint: # denyAfter YYYY-MM-DD # # Operator: # <= | < | == | != | >= | > # # KeyLength: # Integer value of the algorithm's key length in bits # # Note: This property is currently used by the JDK Reference # implementation. It is not guaranteed to be examined and used by other # implementations. # # See "jdk.certpath.disabledAlgorithms" for syntax descriptions. # jdk.jar.disabledAlgorithms=MD2, MD5, RSA keySize < 1024, \ DSA keySize < 1024 # # Algorithm restrictions for Secure Socket Layer/Transport Layer Security # (SSL/TLS/DTLS) processing # # In some environments, certain algorithms or key lengths may be undesirable # when using SSL/TLS/DTLS. This section describes the mechanism for disabling # algorithms during SSL/TLS/DTLS security parameters negotiation, including # protocol version negotiation, cipher suites selection, peer authentication # and key exchange mechanisms. # # Disabled algorithms will not be negotiated for SSL/TLS connections, even # if they are enabled explicitly in an application. # # For PKI-based peer authentication and key exchange mechanisms, this list # of disabled algorithms will also be checked during certification path # building and validation, including algorithms used in certificates, as # well as revocation information such as CRLs and signed OCSP Responses. # This is in addition to the jdk.certpath.disabledAlgorithms property above. # # See the specification of "jdk.certpath.disabledAlgorithms" for the # syntax of the disabled algorithm string. # # Note: The algorithm restrictions do not apply to trust anchors or # self-signed certificates. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # Example: # jdk.tls.disabledAlgorithms=MD5, SSLv3, DSA, RSA keySize < 2048 jdk.tls.disabledAlgorithms=SSLv3, RC4, DES, MD5withRSA, DH keySize < 1024, \ EC keySize < 224, 3DES_EDE_CBC, anon, NULL # # Legacy algorithms for Secure Socket Layer/Transport Layer Security (SSL/TLS) # processing in JSSE implementation. # # In some environments, a certain algorithm may be undesirable but it # cannot be disabled because of its use in legacy applications. Legacy # algorithms may still be supported, but applications should not use them # as the security strength of legacy algorithms are usually not strong enough # in practice. # # During SSL/TLS security parameters negotiation, legacy algorithms will # not be negotiated unless there are no other candidates. # # The syntax of the legacy algorithms string is described as this Java # BNF-style: # LegacyAlgorithms: # " LegacyAlgorithm { , LegacyAlgorithm } " # # LegacyAlgorithm: # AlgorithmName (standard JSSE algorithm name) # # See the specification of security property "jdk.certpath.disabledAlgorithms" # for the syntax and description of the "AlgorithmName" notation. # # Per SSL/TLS specifications, cipher suites have the form: # SSL_KeyExchangeAlg_WITH_CipherAlg_MacAlg # or # TLS_KeyExchangeAlg_WITH_CipherAlg_MacAlg # # For example, the cipher suite TLS_RSA_WITH_AES_128_CBC_SHA uses RSA as the # key exchange algorithm, AES_128_CBC (128 bits AES cipher algorithm in CBC # mode) as the cipher (encryption) algorithm, and SHA-1 as the message digest # algorithm for HMAC. # # The LegacyAlgorithm can be one of the following standard algorithm names: # 1. JSSE cipher suite name, e.g., TLS_RSA_WITH_AES_128_CBC_SHA # 2. JSSE key exchange algorithm name, e.g., RSA # 3. JSSE cipher (encryption) algorithm name, e.g., AES_128_CBC # 4. JSSE message digest algorithm name, e.g., SHA # # See SSL/TLS specifications and "Java Cryptography Architecture Standard # Algorithm Name Documentation" for information about the algorithm names. # # Note: If a legacy algorithm is also restricted through the # jdk.tls.disabledAlgorithms property or the # java.security.AlgorithmConstraints API (See # javax.net.ssl.SSLParameters.setAlgorithmConstraints()), # then the algorithm is completely disabled and will not be negotiated. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # There is no guarantee the property will continue to exist or be of the # same syntax in future releases. # # Example: # jdk.tls.legacyAlgorithms=DH_anon, DES_CBC, SSL_RSA_WITH_RC4_128_MD5 # jdk.tls.legacyAlgorithms= \ K_NULL, C_NULL, M_NULL, \ DH_anon, ECDH_anon, \ RC4_128, RC4_40, DES_CBC, DES40_CBC, \ 3DES_EDE_CBC # # The pre-defined default finite field Diffie-Hellman ephemeral (DHE) # parameters for Transport Layer Security (SSL/TLS/DTLS) processing. # # In traditional SSL/TLS/DTLS connections where finite field DHE parameters # negotiation mechanism is not used, the server offers the client group # parameters, base generator g and prime modulus p, for DHE key exchange. # It is recommended to use dynamic group parameters. This property defines # a mechanism that allows you to specify custom group parameters. # # The syntax of this property string is described as this Java BNF-style: # DefaultDHEParameters: # DefinedDHEParameters { , DefinedDHEParameters } # # DefinedDHEParameters: # "{" DHEPrimeModulus , DHEBaseGenerator "}" # # DHEPrimeModulus: # HexadecimalDigits # # DHEBaseGenerator: # HexadecimalDigits # # HexadecimalDigits: # HexadecimalDigit { HexadecimalDigit } # # HexadecimalDigit: one of # 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f # # Whitespace characters are ignored. # # The "DefinedDHEParameters" defines the custom group parameters, prime # modulus p and base generator g, for a particular size of prime modulus p. # The "DHEPrimeModulus" defines the hexadecimal prime modulus p, and the # "DHEBaseGenerator" defines the hexadecimal base generator g of a group # parameter. It is recommended to use safe primes for the custom group # parameters. # # If this property is not defined or the value is empty, the underlying JSSE # provider's default group parameter is used for each connection. # # If the property value does not follow the grammar, or a particular group # parameter is not valid, the connection will fall back and use the # underlying JSSE provider's default group parameter. # # Note: This property is currently used by OpenJDK's JSSE implementation. It # is not guaranteed to be examined and used by other implementations. # # Example: # jdk.tls.server.defaultDHEParameters= # { \ # FFFFFFFF FFFFFFFF C90FDAA2 2168C234 C4C6628B 80DC1CD1 \ # 29024E08 8A67CC74 020BBEA6 3B139B22 514A0879 8E3404DD \ # EF9519B3 CD3A431B 302B0A6D F25F1437 4FE1356D 6D51C245 \ # E485B576 625E7EC6 F44C42E9 A637ED6B 0BFF5CB6 F406B7ED \ # EE386BFB 5A899FA5 AE9F2411 7C4B1FE6 49286651 ECE65381 \ # FFFFFFFF FFFFFFFF, 2} # # TLS key limits on symmetric cryptographic algorithms # # This security property sets limits on algorithms key usage in TLS 1.3. # When the amount of data encrypted exceeds the algorithm value listed below, # a KeyUpdate message will trigger a key change. This is for symmetric ciphers # with TLS 1.3 only. # # The syntax for the property is described below: # KeyLimits: # " KeyLimit { , KeyLimit } " # # WeakKeyLimit: # AlgorithmName Action Length # # AlgorithmName: # A full algorithm transformation. # # Action: # KeyUpdate # # Length: # The amount of encrypted data in a session before the Action occurs # This value may be an integer value in bytes, or as a power of two, 2^29. # # KeyUpdate: # The TLS 1.3 KeyUpdate handshake process begins when the Length amount # is fulfilled. # # Note: This property is currently used by OpenJDK's JSSE implementation. It # is not guaranteed to be examined and used by other implementations. # jdk.tls.keyLimits=AES/GCM/NoPadding KeyUpdate 2^37 # # Cryptographic Jurisdiction Policy defaults # # Import and export control rules on cryptographic software vary from # country to country. By default, Java provides two different sets of # cryptographic policy files[1]: # # unlimited: These policy files contain no restrictions on cryptographic # strengths or algorithms # # limited: These policy files contain more restricted cryptographic # strengths # # The default setting is determined by the value of the "crypto.policy" # Security property below. If your country or usage requires the # traditional restrictive policy, the "limited" Java cryptographic # policy is still available and may be appropriate for your environment. # # If you have restrictions that do not fit either use case mentioned # above, Java provides the capability to customize these policy files. # The "crypto.policy" security property points to a subdirectory # within /conf/security/policy/ which can be customized. # Please see the /conf/security/policy/README.txt file or consult # the Java Security Guide/JCA documentation for more information. # # YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY # TO DETERMINE THE EXACT REQUIREMENTS. # # [1] Please note that the JCE for Java SE, including the JCE framework, # cryptographic policy files, and standard JCE providers provided with # the Java SE, have been reviewed and approved for export as mass market # encryption item by the US Bureau of Industry and Security. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # crypto.policy=unlimited # # The policy for the XML Signature secure validation mode. The mode is # enabled by setting the property "org.jcp.xml.dsig.secureValidation" to # true with the javax.xml.crypto.XMLCryptoContext.setProperty() method, # or by running the code with a SecurityManager. # # Policy: # Constraint {"," Constraint } # Constraint: # AlgConstraint | MaxTransformsConstraint | MaxReferencesConstraint | # ReferenceUriSchemeConstraint | KeySizeConstraint | OtherConstraint # AlgConstraint # "disallowAlg" Uri # MaxTransformsConstraint: # "maxTransforms" Integer # MaxReferencesConstraint: # "maxReferences" Integer # ReferenceUriSchemeConstraint: # "disallowReferenceUriSchemes" String { String } # KeySizeConstraint: # "minKeySize" KeyAlg Integer # OtherConstraint: # "noDuplicateIds" | "noRetrievalMethodLoops" # # For AlgConstraint, Uri is the algorithm URI String that is not allowed. # See the XML Signature Recommendation for more information on algorithm # URI Identifiers. For KeySizeConstraint, KeyAlg is the standard algorithm # name of the key type (ex: "RSA"). If the MaxTransformsConstraint, # MaxReferencesConstraint or KeySizeConstraint (for the same key type) is # specified more than once, only the last entry is enforced. # # Note: This property is currently used by the JDK Reference implementation. It # is not guaranteed to be examined and used by other implementations. # jdk.xml.dsig.secureValidationPolicy=\ disallowAlg http://www.w3.org/TR/1999/REC-xslt-19991116,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#rsa-md5,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#hmac-md5,\ disallowAlg http://www.w3.org/2001/04/xmldsig-more#md5,\ maxTransforms 5,\ maxReferences 30,\ disallowReferenceUriSchemes file http https,\ minKeySize RSA 1024,\ minKeySize DSA 1024,\ minKeySize EC 224,\ noDuplicateIds,\ noRetrievalMethodLoops # # Serialization process-wide filter # # A filter, if configured, is used by java.io.ObjectInputStream during # deserialization to check the contents of the stream. # A filter is configured as a sequence of patterns, each pattern is either # matched against the name of a class in the stream or defines a limit. # Patterns are separated by ";" (semicolon). # Whitespace is significant and is considered part of the pattern. # # If the system property jdk.serialFilter is also specified, it supersedes # the security property value defined here. # # If a pattern includes a "=", it sets a limit. # If a limit appears more than once the last value is used. # Limits are checked before classes regardless of the order in the # sequence of patterns. # If any of the limits are exceeded, the filter status is REJECTED. # # maxdepth=value - the maximum depth of a graph # maxrefs=value - the maximum number of internal references # maxbytes=value - the maximum number of bytes in the input stream # maxarray=value - the maximum array length allowed # # Other patterns, from left to right, match the class or package name as # returned from Class.getName. # If the class is an array type, the class or package to be matched is the # element type. # Arrays of any number of dimensions are treated the same as the element type. # For example, a pattern of "!example.Foo", rejects creation of any instance or # array of example.Foo. # # If the pattern starts with "!", the status is REJECTED if the remaining # pattern is matched; otherwise the status is ALLOWED if the pattern matches. # If the pattern contains "/", the non-empty prefix up to the "/" is the # module name; # if the module name matches the module name of the class then # the remaining pattern is matched with the class name. # If there is no "/", the module name is not compared. # If the pattern ends with ".**" it matches any class in the package and all # subpackages. # If the pattern ends with ".*" it matches any class in the package. # If the pattern ends with "*", it matches any class with the pattern as a # prefix. # If the pattern is equal to the class name, it matches. # Otherwise, the status is UNDECIDED. # #jdk.serialFilter=pattern;pattern # # RMI Registry Serial Filter # # The filter pattern uses the same format as jdk.serialFilter. # This filter can override the builtin filter if additional types need to be # allowed or rejected from the RMI Registry or to decrease limits but not # to increase limits. # If the limits (maxdepth, maxrefs, or maxbytes) are exceeded, the object is rejected. # # Each non-array type is allowed or rejected if it matches one of the patterns, # evaluated from left to right, and is otherwise allowed. Arrays of any # component type, including subarrays and arrays of primitives, are allowed. # # Array construction of any component type, including subarrays and arrays of # primitives, are allowed unless the length is greater than the maxarray limit. # The filter is applied to each array element. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # The built-in filter allows subclasses of allowed classes and # can approximately be represented as the pattern: # #sun.rmi.registry.registryFilter=\ # maxarray=1000000;\ # maxdepth=20;\ # java.lang.String;\ # java.lang.Number;\ # java.lang.reflect.Proxy;\ # java.rmi.Remote;\ # sun.rmi.server.UnicastRef;\ # sun.rmi.server.RMIClientSocketFactory;\ # sun.rmi.server.RMIServerSocketFactory;\ # java.rmi.activation.ActivationID;\ # java.rmi.server.UID # # RMI Distributed Garbage Collector (DGC) Serial Filter # # The filter pattern uses the same format as jdk.serialFilter. # This filter can override the builtin filter if additional types need to be # allowed or rejected from the RMI DGC. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # # The builtin DGC filter can approximately be represented as the filter pattern: # #sun.rmi.transport.dgcFilter=\ # java.rmi.server.ObjID;\ # java.rmi.server.UID;\ # java.rmi.dgc.VMID;\ # java.rmi.dgc.Lease;\ # maxdepth=5;maxarray=10000 # CORBA ORBIorTypeCheckRegistryFilter # Type check enhancement for ORB::string_to_object processing # # An IOR type check filter, if configured, is used by an ORB during # an ORB::string_to_object invocation to check the veracity of the type encoded # in the ior string. # # The filter pattern consists of a semi-colon separated list of class names. # The configured list contains the binary class names of the IDL interface types # corresponding to the IDL stub class to be instantiated. # As such, a filter specifies a list of IDL stub classes that will be # allowed by an ORB when an ORB::string_to_object is invoked. # It is used to specify a white list configuration of acceptable # IDL stub types which may be contained in a stringified IOR # parameter passed as input to an ORB::string_to_object method. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be examined and used by other implementations. # #com.sun.CORBA.ORBIorTypeCheckRegistryFilter=binary_class_name;binary_class_name # # JCEKS Encrypted Key Serial Filter # # This filter, if configured, is used by the JCEKS KeyStore during the # deserialization of the encrypted Key object stored inside a key entry. # If not configured or the filter result is UNDECIDED (i.e. none of the patterns # matches), the filter configured by jdk.serialFilter will be consulted. # # If the system property jceks.key.serialFilter is also specified, it supersedes # the security property value defined here. # # The filter pattern uses the same format as jdk.serialFilter. The default # pattern allows java.lang.Enum, java.security.KeyRep, java.security.KeyRep$Type, # and javax.crypto.spec.SecretKeySpec and rejects all the others. jceks.key.serialFilter = java.base/java.lang.Enum;java.base/java.security.KeyRep;\ java.base/java.security.KeyRep$Type;java.base/javax.crypto.spec.SecretKeySpec;!* # # Enhanced exception message information # # By default, exception messages should not include potentially sensitive # information such as file names, host names, or port numbers. This property # accepts one or more comma separated values, each of which represents a # category of enhanced exception message information to enable. Values are # case-insensitive. Leading and trailing whitespaces, surrounding each value, # are ignored. Unknown values are ignored. # # NOTE: Use caution before setting this property. Setting this property # exposes sensitive information in Exceptions, which could, for example, # propagate to untrusted code or be emitted in stack traces that are # inadvertently disclosed and made accessible over a public network. # # The categories are: # # hostInfo - IOExceptions thrown by java.net.Socket and the socket types in the # java.nio.channels package will contain enhanced exception # message information # # The property setting in this file can be overridden by a system property of # the same name, with the same syntax and possible values. # #jdk.includeInExceptions=hostInfo # # Policies for distrusting Certificate Authorities (CAs). # # This is a comma separated value of one or more case-sensitive strings, each # of which represents a policy for determining if a CA should be distrusted. # The supported values are: # # SYMANTEC_TLS : Distrust TLS Server certificates anchored by a Symantec # root CA and issued after April 16, 2019 unless issued by one of the # following subordinate CAs which have a later distrust date: # 1. Apple IST CA 2 - G1, SHA-256 fingerprint: # AC2B922ECFD5E01711772FEA8ED372DE9D1E2245FCE3F57A9CDBEC77296A424B # Distrust after December 31, 2019. # 2. Apple IST CA 8 - G1, SHA-256 fingerprint: # A4FE7C7F15155F3F0AEF7AAA83CF6E06DEB97CA3F909DF920AC1490882D488ED # Distrust after December 31, 2019. # # Leading and trailing whitespace surrounding each value are ignored. # Unknown values are ignored. If the property is commented out or set to the # empty String, no policies are enforced. # # Note: This property is currently used by the JDK Reference implementation. # It is not guaranteed to be supported by other SE implementations. Also, this # property does not override other security properties which can restrict # certificates such as jdk.tls.disabledAlgorithms or # jdk.certpath.disabledAlgorithms; those restrictions are still enforced even # if this property is not enabled. # jdk.security.caDistrustPolicies=SYMANTEC_TLS OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/logback.xml000066400000000000000000000006211527232126200265650ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/logging.properties000066400000000000000000000001621527232126200302050ustar00rootroot00000000000000# register SLF4JBridgeHandler as handler for the j.u.l. root logger handlers = org.slf4j.bridge.SLF4JBridgeHandlerOpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/puppetlabs/000077500000000000000000000000001527232126200266215ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/puppetlabs/trapperkeeper/000077500000000000000000000000001527232126200314725ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/puppetlabs/trapperkeeper/services/000077500000000000000000000000001527232126200333155ustar00rootroot00000000000000webserver/000077500000000000000000000000001527232126200352425ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/puppetlabs/trapperkeeper/servicesrequest-logging.xml000066400000000000000000000004441527232126200411020ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/dev-resources/puppetlabs/trapperkeeper/services/webserver %h %l %u %user %date "%r" %s %b %mdc{mdc-test:-default-mdc-value} OpenVoxProject-trapperkeeper-webserver-8a905f4/doc/000077500000000000000000000000001527232126200224215ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/doc/jetty-config.md000066400000000000000000000473111527232126200253530ustar00rootroot00000000000000## Configuring The Webserver Service The `webserver` section in your Trapperkeeper configuration files configures an embedded HTTP server inside trapperkeeper. ### `host` This sets the hostname to listen on for _unencrypted_ HTTP traffic. If not supplied, we bind to `localhost`, which will reject connections from anywhere but the server process itself. To listen on all available interfaces, use `0.0.0.0`. ### `port` This sets what port to use for _unencrypted_ HTTP traffic. If not supplied, but `host` is supplied, a value of 8080 will be used. If neither host nor port is supplied, we won't listen for unencrypted traffic at all. ### `acceptor-threads` This sets the number of threads that the webserver will dedicate to accepting socket connections for _unencrypted_ HTTP traffic. Defaults to the number of virtual cores on the host divided by 8, with a minimum of 1 and maximum of 4. ### `selector-threads` This sets the number of selectors that the webserver will dedicate to processing events on connected sockets for unencrypted HTTPS traffic. Defaults to the minimum of: virtual cores on the host divided by 2 or `max-threads` divided by 16, with a minimum of 1. ### `max-threads` This sets the maximum number of threads assigned to responding to HTTP and/or HTTPS requests for a single webserver, effectively changing how many concurrent requests can be made at one time. Defaults to 200. Each webserver instance requires a minimum number of threads in order to boot properly. The minimum number is calculated as: ~~~~ (number of "acceptor-threads" for each port) + (number of "selector-threads" for each port) + (number of "reserved-threads" for each port) + 2 "worker" threads ~~~~ Reserved threads are unconfigurable and default to the minimum of the number of virtual cores or `max-threads` divided by 10, with a minimum of one thread allocated. Because reserved threads (and if not explicitly configured, selector threads) scale with max-threads, lowering the max-threads will cause fewer resources to be allocated to handling reqeusts on each port down to a threshold calculable by the forumalas above. If the configured value for `max-threads` is less than the minimum required value, server startup will fail with an `IllegalStateException`, with a message containing the words "Insufficient configured threads". Note that each web request must be processed on a "worker" thread which is separate from the acceptor and selector threads. "1" is the minimum number of worker threads required to process incoming web requests. The `max-threads` value should be large enough that the server can allocate all of the selector and acceptor threads that it needs and yet still have a sufficient number of worker threads left over for handling concurrent web requests. ### `queue-max-size` This can be used to set an upper-bound on the size of the worker queue that the web server uses to temporarily store incoming client connections before they can be serviced. This value defaults to the maximum value of a 32-bit signed integer, 2147483647. A request which is rejected by the web server because the queue is full would be seen by the client as having initially connected to the server socket at the TCP layer but having been closed almost immediately afterward by the server with no HTTP layer response body. ### `request-body-max-size` This sets the maximum size, in bytes, of the body for an HTTP request. The size of the request body is determined from the value for the request's HTTP Content-Length header. If the Content-Length exceeds the configured value, Jetty will return an HTTP 413 Error response. If this setting is not configured and/or the request does not provide a Content-Length header, Jetty will pass the request through to underlying handlers (bypassing Content-Length evaluation). ### `request-header-max-size` This sets the maximum size of an HTTP Request Header. If a header is sent that exceeds this value, Jetty will return an HTTP 431 Error response. This defaults to 8192 bytes, and only needs to be configured if an exceedingly large header is being sent in an HTTP Request. ### `so-linger-seconds` This setting has been removed. The option used in Jetty no longer attempts to set the SO_LINGER for the socket as of v9.4.12. The Jetty maintainers discovered this option has undefined behavior on non-blocking connections (and all underlying connections became non-blocking in Jetty 9.0). The actual behavior, though undefined by the Java spec, also changes between Java versions (so a user on Java 8 will see different behavior on Java 11) and has been reported to the Jetty community as a source of bugs on some platforms. ### `idle-timeout-milliseconds` This optional setting can be used to control how long Jetty will allow a connection to be held open by a client without any activity on the socket. If a connection is idle for longer than this value, Jetty will forcefully close it from the server side. Jetty's default value for this setting is 30 seconds. Note that Jetty will not automatically close the connection if the idle timeout is reached while Jetty is still actively processing a client request. ### `ssl-host` This sets the hostname to listen on for _encrypted_ HTTPS traffic. If not supplied, we bind to `localhost`. To listen on all available interfaces, use `0.0.0.0`. ### `ssl-port` This sets the port to use for _encrypted_ HTTPS traffic. If not supplied, but `ssl-host` is supplied, a value of 8081 will be used for the https port. If neither ssl-host nor ssl-port is supplied, we won't listen for encrypted traffic at all. ### `ssl-acceptor-threads` This sets the number of threads that the webserver will dedicate to accepting socket connections for _encrypted_ HTTPS traffic. Defaults to the number of virtual cores on the host divided by 8, with a minimum of 1 and maximum of 4. ### `ssl-selector-threads` This sets the number of selectors that the webserver will dedicate to processing events on connected sockets for encrypted HTTPS traffic. Defaults to the number of virtual cores on the host divided by 2, with a minimum of 1 and maximum of 4. The number of selector threads actually used by Jetty is twice the number of selectors requested. For example, if a value of 3 is specified for the `ssl-selector-threads` setting, Jetty will actually use 6 selector threads. ### `ssl-cert` This sets the path to the server certificate PEM file used by the web service for HTTPS. During the SSL handshake for a connection, certificates extracted from this file are presented to the client for the client's use in validating the server. This file may contain a single certificate or a chain of certificates ordered from the end certificate first to the most-root certificate last. For example, a certificate chain could contain: * An end certificate * An intermediate CA certificate with which the end certificate was issued * A root CA certificate with which the intermediate CA certificate was issued In the PEM file, the end certificate should appear first, the intermediate CA certificate should appear second, and the root CA certificate should appear last. If a chain is present, it is not required to be complete. If a path has been specified for the `ssl-cert-chain` setting, the server will construct the cert chain starting with the first certificate found in the `ssl-cert` PEM and followed by any certificates in the `ssl-cert-chain` PEM. In the latter case, any certificates in the `ssl-cert` PEM beyond the first one would be ignored. > **Note:** This setting overrides the alternate configuration settings `keystore` and `key-password`. ### `ssl-cert-chain` This sets the path to a PEM with CA certificates for use in presenting a client with the server's chain of trust. Certs found in this PEM file are appended after the first certificate from the `ssl-cert` PEM in the construction of the certificate chain. This is an optional setting. The certificates in the `ssl-cert-chain` PEM file should be ordered from the least-root CA certificate first to the most-root CA certificate last. For example, a certificate chain could contain: * An end certificate * An intermediate CA certificate with which the end certificate was issued * A root CA certificate with which the intermediate CA certificate was issued The end certificate should appear in the `ssl-cert` PEM file. In the `ssl-cert-chain` PEM file, the intermediate CA certificate should appear first and the root CA certificate should appear last. The chain is not required to be complete. > **Note:** This setting overrides the alternate configuration settings `keystore` and `key-password`. ### `ssl-key` This sets the path to the private key PEM file that corresponds with the `ssl-cert`, it used by the web service for HTTPS. > **Note:** This setting overrides the alternate configuration settings `keystore` and `key-password`. ### `ssl-ca-cert` This sets the path to the CA certificate PEM file used for client authentication. The PEM file may contain one or more CA certificates. Authorized clients must have been signed - either directly or via an intermediate CA - using one of the CA certificates in the PEM file. > **Note:** This setting overrides the alternate configuration settings `truststore` and `trust-password`. ### `keystore` This sets the path to a Java keystore file containing the key and certificate to be used for HTTPS. ### `key-password` This sets the passphrase to use for unlocking the keystore file. ### `truststore` This describes the path to a Java keystore file containing the CA certificate(s) for your infrastructure. ### `trust-password` This sets the passphrase to use for unlocking the truststore file. ### `cipher-suites` Optional. The cryptographic ciphers to allow for incoming SSL connections. This may be formatted either as a list (in a HOCON configuration file) or a comma-separated string. Valid names are listed in the [official JDK cryptographic providers documentation](http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SupportedCipherSuites); you'll need to use the all-caps cipher suite name. If not supplied, trapperkeeper uses this list of cipher suites: - `TLS_AES_128_GCM_SHA256` - `TLS_AES_256_GCM_SHA384` - `TLS_CHACHA20_POLY1305_SHA256` - `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` - `TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384` - `TLS_DHE_RSA_WITH_AES_128_GCM_SHA256` - `TLS_DHE_RSA_WITH_AES_256_GCM_SHA384` ### `ssl-protocols` Optional. The protocols to allow for incoming SSL connections. This may be formatted either as a list (in a HOCON configuration file) or a comma-separated string. Valid names are listed in the [official JDK cryptographic protocol documentation](http://docs.oracle.com/javase/7/docs/technotes/guides/security/SunProviders.html#SunJSSEProvider); you'll need to use the names with verbatim capitalization. For example: `TLSv1, TLSv1.1, TLSv1.2`. If not supplied, trapperkeeper uses this list of SSL protocols: - `TLSv1.3` - `TLSv1.2` ### `client-auth` Optional. This determines the mode that the server uses to validate the client's certificate for incoming SSL connections. One of the following values may be specified: * `need` - The server will request the client's certificate and the certificate must be provided and be valid. The certificate must have been issued by a Certificate Authority whose certificate resides in the `truststore`. * `want` - The server will request the client's certificate. A certificate, if provided by the client, must have been issued by a Certificate Authority whose certificate resides in the `truststore`. If the client does not provide a certificate, the server will still consider the client valid. * `none` - The server will not request a certificate from the client and will consider the client valid. If a value is not provided for this setting, `need` will be used as the default value. ### `ssl-crl-path` Optional. This describes a path to a Certificate Revocation List file. Incoming SSL connections will be rejected if the client certificate matches a revocation entry in the file. ### `allow-renegotiation` Optional. This controls whether the web server will allow client initiated SSL/TLS renegotiations. By default this will be disabled since allowing client to renegotiate is a vulnerability causing denial of service and information disclosure in certain cases. It can be over-ridden by setting this parameter to true. ### `static-content` Optional. This is a list of static content to be added to the server as context handlers during initialization. Each item in this list should be a map containing two keys. The first, `resource`, is the path to the resource you want added as a context handler (the equivalent of the `base-path` argument of the `add-context-handler` service function). The second, `path`, is the URL endpoint at which you want to mount the context handler (the equivalent of the `context-path` argument of the `add-context-handler` service function). For example, say you have a `web-assets` directory containing a file called `image.jpg`. If your configuration were like so: ``` webserver: { port: 8080 static-content: [{resource: "./web-assets" path: "/assets"}] } ``` Then the static content in the `web-assets` directory would be mounted at the URL endpoint `"/assets"` on your server during initialization, and you could access the contents of `image.jpg` by visiting `"http://localhost:8080/assets/image.jpg"`. By default, symbolic links will not be served by the Jetty Webservice. However, if you have a symbolic link that you want to serve as static content, you can add an extra option, `follow-links`, to the specification for a piece of static content. The value of this should be a boolean, and if set to true, symbolic links will be served. For example, say that you have a symbolic link in your `web-assets` directory, `image-link`, that links to the `image.jpg` file. If you want this to be served, you would configure your static content like so: ``` webserver: { port: 8080 static-content: [{resource: "./web-assets" path: "/assets" follow-links: true}] } ``` Since `follow-links` is set to true, `image-link` will now be served, and can be accessed by visiting `"http://localhost:8080/assets/image-link"`. ### `gzip-enable` Optional. This controls whether or not the webserver could compress the response body for any request using Gzip encoding. A value of `false` would prevent the server from using Gzip encoding the response body for all requests. If this option is not specified or is specified with a value of `true`, the webserver "could" Gzip encode the response body. Note that in order for Gzip encoding to be used, a client would also need to include in the request an "Accept-Encoding" HTTP header containing the value "gzip". The webserver also may use other heuristics to avoid Gzip encoding the response body independent of the configuration of this setting. For example, the webserver may skip compression for a sufficiently small response body. ### `access-log-config` Optional. This is a path to an XML file containing configuration information for the `Logback-access` module. If present, a logger will be set up to log information about any HTTP requests Jetty receives according to the logging configuration, as long as the XML file pointed to exists and is valid. Information on configuring the `Logback-access` module is available [here](http://logback.qos.ch/access.html#configuration). An example configuration file can be found [here](request-logging-example-config.xml). This example configures a `FileAppender` that outputs to a file, `access.log`, in the `dev-resources` directory. The `pattern` element configures the output format to match the [Apache Combined Log Format](https://httpd.apache.org/docs/2.4/logs.html#combined). See the [Logback access layout documentation](https://logback.qos.ch/manual/layouts.html#logback-access) for a list of other items that can be added to the `pattern` element. TrapperKeeper configures the `Logback-access` library with additional support for the SLF4J [Mapped Diagnostic Context](https://logback.qos.ch/manual/mdc.html) (MDC). This support allows the `%X` and `%mdc` conversion words to be used in the `Logback-access` `pattern` which behave as described in the [docs for Logback-classic](https://logback.qos.ch/manual/layouts.html#mdc). Jetty is configured to clear any items added to the MDC at the end of each request so that incorrect data won't show up in subsequent requests that are handled by the same worker thread. ### `shutdown-timeout-seconds` Optional. This is an integer representing the desired graceful stop timeout in seconds. Defaults to 30 seconds. ## Configuring multiple webservers on isolated ports It is possible to configure multiple webservers on isolated ports within a single Jetty webservice. In order to configure multiple webservers, change the `webserver` section of your Trapperkeeper configuration files to be a nested map. Each key in this map is the id of a server, and its value is the configuration for that server. For example, say you wanted to configure two servers on localhost, one on port 9000 and one on port 10000. The webserver section of your configuration file would look something like this: ``` webserver: { bar: { host: localhost port: 9000 } foo: { host: localhost port: 10000 } } ``` This configuration would cause the Jetty service to create two different Jetty servers on isolated ports. You can then specify which server you would like to add handlers to when calling the Jetty service functions, and they will be added to the server you specify. Please note that, with the above configuration, you MUST specify a server-id when calling a service function, or else the operation will fail. If you would like to have a multi-server configuration and NOT specify a server-id when calling some service functions, you can optionally specify a default server in your configuration file. Then, if no server-id is specified when performing an operation, the operation will automatically be performed on the default server. To specify a default server, add a `:default-server` key with a value of `true` to the configuration information for one of your servers in your trapperkeeper configuration. For example: ``` webserver: { bar: { host: localhost port: 9000 default-server: true } foo: { host: localhost port: 10000 } } ``` The above configuration would set up two servers as in the previous example, except the server with id `:bar` would be set as the default server. Calling a service function without specifying a server-id will cause the operation to be performed on the server with id `:bar`. Please note that only one server can be specified as the default server. Please also note that setting a default server is optional. It is only required if you are planning to call a service function without passing in a server-id in a multi-server set-up. Note that you are NOT limited to two servers and can configure more according to your needs. Also note that you can still set the `webserver` section of your configuration to be an un-nested map containing a single webserver configuration, like so ``` webserver: { host: localhost port: 9000 } ``` In this case, the Jetty Service will simply create a single webserver and give it id `:default`, and will automatically make this server the default server. ### `jmx-enable` Optional. When enabled this setting will register the Jetty 10 MBeans so they are visible via JMX. Useful for monitoring the state of your Jetty 10 instance while it is running; for monitoring and debugging purposes. Defaults to `true`. OpenVoxProject-trapperkeeper-webserver-8a905f4/doc/request-logging-example-config.xml000066400000000000000000000007371527232126200311620ustar00rootroot00000000000000 ./dev-resources/access.log %h %l %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}" OpenVoxProject-trapperkeeper-webserver-8a905f4/doc/test-utils.md000066400000000000000000000035111527232126200250600ustar00rootroot00000000000000# TrapperKeeper Webserver Service Test Utils The trapperkeeper webserver service library provides some [utility code](../test/clj/puppetlabs/trapperkeeper/testutils) for use in tests. The code is available in a separate "test" jar that you may depend on by using a classifier in your project dependencies. ```clojure (defproject yourproject "1.0.0" ... :profiles {:dev {:dependencies [[org.openvoxproject/trapperkeeper-webserver "x.y.z" :classifier "test"]]}}) ``` The test jar contains a macro to assist in testing the functionality of a ring application. You can find the macro in [webserver.clj](../test/puppetlabs/trapperkeeper/testutils/webserver.clj). ### with-test-webserver The `with-test-webserver` macro starts up a new web server which is bound to a random unused port, and attaches a provided Ring handler function. When the test is completed `with-test-webserver` also handles shutting down the web server. The first parameter provided to the `with-test-webserver` macro is a ring handler function (see [ring concepts](https://github.com/ring-clojure/ring/wiki/Concepts)) which will generally by a handler that exists in your _trapperkeeper_ application somewhere. The second parameter is an identifier which will contain the port number that the web server was started on. Generally, inside the body of the `with-test-webserver` macro a number of web requests are made and their responses are examined for correctness. For example: ```clojure (with-test-webserver app port (testing "a gzipped response when requests" ;; The client/get function asks for compression by default (let [resp (http-client/get (format "http://localhost:%d/" port))] (is (= (resp :body) body)) (is (= (get-in resp [:headers "content-encoding"]) "gzip") (format "Expected gzipped response, got this response: %s" resp)))) ``` OpenVoxProject-trapperkeeper-webserver-8a905f4/doc/webrouting-config.md000066400000000000000000000055311527232126200263770ustar00rootroot00000000000000## Configuring The Webrouting Service The `web-router-service` section in your Trapperkeeper configuration files configures the endpoints for your webrouter service. Each key in the `web-router-service` section is the namespaced symbol of a service. The value stored in this key can be one of two things. If only specifying one endpoint for a particular service, this value can be a string containing a URL endpoint. This will be the only endpoint available for the service it is configured for, and it will automatically be assigned route-id `:default`. This can be done like so: ``` web-router-service: { "puppetlabs.foo/foo-service": "/foo" } ``` It is also possible to configure multiple web endpoints. In this case, the value will be a map instead of a string. Each key in this map will contain a URL endpoint stored in a string. They key is the route-id for that endpoint. This can be done like so: ``` web-router-service: { "puppetlabs.foo/foo-service": { foo: "/foo" bar: "/bar" } } ``` In this case, two endpoints will be configured for the `foo-service`. `"/foo"` will have route-id `:foo`, and `"/bar"` will have route-id `:bar`. Handlers can be added to the `"/bar"` endpoint by explicitly specifying `:bar` as the `route-id` when adding a handler. Please see [Trapperkeeper Webrouting Service](webrouting-service.md) for more information. In the case where you have configured multiple servers, you can configure the webrouting service to add specific endpoints to specific servers. For example, say you have two servers, one with id `:foo` and one with id `:bar`. Say you want the endpoint for a service to be added to the server with id `:foo`. You could do this like so: ``` web-router-service: { "puppetlabs.foo/foo-service": { route: "/foo" server: "foo" } } ``` You can do the same thing when you have multiple routes configured for a service: ``` web-router-service: { "puppetlabs.foo/foo-service": { foo: { route: "/foo" server: "foo" } bar: { route: "/bar" server: "bar" } } } ``` In this case, adding a handler to endpoint `:foo` would add it to the server with id `:foo` at path "/foo". Adding a handler to endpoint `bar` would add it to the server with id `:bar` at path "/bar". Note that, if no server is specified for an endpoint and there are multiple servers, the endpoint will be added to the default server. If no default server is set, a server MUST be provided for every endpoint. Also note that, because the webrouting service is built on top of the webserver service, the webserver service will need to be included in your `bootstrap.cfg` file, and the webserver service will need to be configured in your trapperkeeper configuration files. Please see [Configuring the Webserver](jetty-config.md) for more details. OpenVoxProject-trapperkeeper-webserver-8a905f4/doc/webrouting-service.md000066400000000000000000000146761527232126200266040ustar00rootroot00000000000000## Trapperkeeper Webrouting Service This project additionally provides a webrouting service, which acts as a wrapper around the Trapperkeeper Webserver Service, also contained in this project. This service is for use with the [trapperkeeper service framework.](https://github.com/openvoxproject/trapperkeeper) The Webrouting Service is an optional service that allows you to manage the configuration of your web service URLs in a different manner. It is a thin wrapper around the Webserver Service, and it allows you to consolidate all of your URL endpoints in a single section of your trapperkeeper configuration. When using the Webserver Service to directly register web endpoints, the endpoints get scattered throughout the code base, and it can be difficult to determine what endpoints are running in your server and which services registered them. With the webrouting service, all this information is stored in your configuration file. It is easy to determine which endpoints are running on your server and which services registered those endpoints. For example: ``` web-router-service: { "puppetlabs.foo/foo-service": "/foo" "puppetlabs.bar/bar-service": { bar: "/bar" baz: "/baz" } } ``` The services specified in the above configuration would use the Webrouting Service instead of the Webserver Service to register web endpoints. A developer/user/administrator can simply look at the trapperkeeper configuration and determine there are web endpoints registered at '/foo', '/bar/, and '/baz', and that these are registered in the clojure namespaces 'puppetlabs.foo' and 'puppetlabs.bar'. To use this service in your trapperkeeper application, simply add this project as a dependency in your leiningen project file, and then add the webrouting service to your [`bootstrap.cfg`](https://github.com/openvoxproject/trapperkeeper#bootstrapping) file, via: puppetlabs.trapperkeeper.services.webrouting.webrouting-service/webrouting-service The webrouting service is configured via the [trapperkeeper configuration service](https://github.com/openvoxproject/trapperkeeper#configuration-service). Please see [Configuring the Webrouting Service](webrouting-config.md) for information on how to configure the webrouting service. ### Service Protocol This is the protocol for the current implementation of the `:WebroutingService`: ```clj (defprotocol WebroutingService (get-route [this svc] [this svc route-id]) (get-server [this svc] [this svc route-id]) (add-context-handler [this svc context-path] [this svc context-path options]) (add-ring-handler [this svc handler] [this svc handler options]) (add-servlet-handler [this svc servlet] [this svc servlet options]) (add-war-handler [this svc war] [this svc war options]) (add-websocket-handler [this svc handlers] [this svc handlers options]) (add-proxy-route [this svc target] [this svc target options]) (override-webserver-settings! [this overrides] [this server-id overrides]) (get-registered-endpoints [this] [this server-id]) (log-registered-endpoints [this] [this server-id]) (join [this] [this server-id])) ``` #### `get-route` This function allows you to get the web-route for a particular service as configured in your configuration file. The one-argument version will return the web route configured for the current service in a single-route configuration. The two argument version will return the web route configured for the current service with the id you specify. Note that the one argument version cannot be used with a service that has multiple webroutes configured. #### `get-server` This function allows you to get the server for a particular service as configured in your configuration file. The one-argument version will return the server configured for the current service in a single-route configuration. The two argument version will return the server configured for the web route with the `route-id` that you specify configured for the current service. Note that both the one and two argument versions will return nil if the service does not have a server value configured. #### Other functions The functions `override-webserver-settings!`, `get-registered-endpoints`, `log-registered-endpoints`, and `join` all work in the exact same way as their corresponding functions in the webserver service, and are there so that you don't need to specify a dependency on the Webserver Service. The other functions do the same thing as their Webserver Service counterparts. However, instead of taking an explicit path as an argument, these functions take a service, `svc`. `svc` should be the service calling the function. Instead of having an explicit endpoint passed in as an argument, these functions will use the service given to them to find the endpoint configured for that service in the configuration file. So, for example, with the Webserver service, you would call ```clj (add-ring-handler my-app "/my-app") ``` which would add the ring handler `my-app` to the endpoint `"/my-app"`. With the webrouting service, however, you would call ```clj (add-ring-handler this my-app) ``` which would find the endpoint configured for the current service in the configuration file, then register the ring handler `my-app` at that endpoint. The options map for each of these functions is identical to those in the corresponding webserver service functions, with two exceptions. First, they can take an additional, optional key, `:route-id`. This is used when multiple endpoints are configured for a specific service, with its value being the id of the specific endpoint you want to add the handler to. In a multiroute configuration, a route-id MUST be specified or the operation will fail. Second, `:server-id` is a disallowed key in this options map. Specifying a specific server to which to add an endpoint is handled in the configuration of the webrouting service. As an example, say you decide to add two endpoints using a specific service, and you have two endpoints configured for that service. One is endpoint `"/foo"` and is kept at key `:foo`. The other is endpoint `"/bar"` and is kept at key `:bar`. If you were to call ```clj (add-ring-handler this my-app {:route-id :foo) ``` the ring handler `my-app` would be registered at endpoint `"/foo"`. However, if you were to call ```clj (add-ring-handler this my-app {:route-id :bar}) ``` the ring handler `my-app` would be registered at endpoint `"/bar"`. For information on how to configure multiple endpoints, please see [Configuring the Webrouting Service](webrouting-config.md). OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/000077500000000000000000000000001527232126200234725ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/000077500000000000000000000000001527232126200267135ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/README.md000066400000000000000000000014771527232126200302030ustar00rootroot00000000000000Sample Trapperkeeper Multiserver Web App ----------------------------------------- To run the app, use this command: ```sh lein trampoline run --config examples/multiserver_app/multiserver-example.conf \ --bootstrap-config examples/multiserver_app/bootstrap.cfg ``` Open ``` http://localhost:8080/hello ``` in your browser to see the famous Hello World message. Open ``` http://localhost:9000/hello ``` in your browser to see the same message. Note that this is on a separate server on a different port. Open ``` http://localhost:9000/goodbye ``` in your browser to see a "Goodbye world" message. Note that this response is NOT displayed at address ``` http://localhost:8080/goodbye ``` due to the fact that it was added specifically to the server on port 9000 and NOT the server on port 8080.OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/bootstrap.cfg000066400000000000000000000004061527232126200314110ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service puppetlabs.trapperkeeper.services.webserver.jetty-service/jetty-service examples.multiserver-app.example-services/hello-web-service examples.multiserver-app.example-services/hello-proxy-service OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/logback.xml000066400000000000000000000004511527232126200310370ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/multiserver-example.conf000066400000000000000000000004611527232126200335750ustar00rootroot00000000000000global: { # Points to a logback config file logging-config: examples/multiserver_app/logback.xml } nrepl: { enabled: true } webserver: { bar: { port: 8080 default-server: true } foo: { port: 9000 } } hello-web: { url-prefix = /hello } OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/src/000077500000000000000000000000001527232126200275025ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/src/examples/000077500000000000000000000000001527232126200313205ustar00rootroot00000000000000multiserver_app/000077500000000000000000000000001527232126200344625ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/src/examplesexample_services.clj000066400000000000000000000030701527232126200405120ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/multiserver_app/src/examples/multiserver_app(ns examples.multiserver-app.example-services (:require [clojure.tools.logging :as log] [puppetlabs.trapperkeeper.core :refer [defservice]])) (defservice hello-web-service [[:ConfigService get-in-config] [:WebserverService add-ring-handler]] (init [this context] (log/info "Initializing hello webservice") (let [url-prefix (get-in-config [:hello-web :url-prefix])] ; Since we're using add-ring-handler, the ring handler will be added to the :default ; server specified in the config file automatically (add-ring-handler (fn [req] {:status 200 :headers {"Content-Type" "text/plain"} :body "Hello, World!"}) url-prefix) (assoc context :url-prefix url-prefix)))) (defservice hello-proxy-service [[:ConfigService get-in-config] [:WebserverService add-proxy-route add-ring-handler]] (init [this context] (log/info "Initializing hello webservice") (let [url-prefix (get-in-config [:hello-web :url-prefix])] ; Since we're using the -to versions of the below functions and are specifying ; server-id :foo, these will be added to the :foo server specified in the ; config file. (add-proxy-route {:host "localhost" :port 8080 :path "/hello"} "/hello" {:server-id :foo}) (add-ring-handler (fn [req] {:status 200 :headers {"Content-Type" "text/plain"} :body "Goodbye world"}) "/goodbye" {:server-id :foo}) (assoc context :url-prefix url-prefix)))) OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/000077500000000000000000000000001527232126200252715ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/README.md000066400000000000000000000250731527232126200265570ustar00rootroot00000000000000# Simple Web Service Example This example demonstrates how to create a simple set of web services which both depend upon a hit counter service for generating content. When run, this code will attach two endpoints, `/bert` and `/ernie` which will generate a simple block of HTML that displays separate hit counters for each service. All code needed to execute this example is located in `examples/ring_app`. The Clojure code is contained in the `example_services.clj` file. And now, a few quick housekeeping items before we get to the code... ## Launching trapperkeeper and running the app To start up _trapperkeeper_ and launch the sample application, use the following _lein_ command while in the _trapperkeeper-webserver_ home directory: ```sh lein trampoline run --config examples/ring_app/ring-example.conf \ --bootstrap-config examples/ring_app/bootstrap.cfg ``` Once _trapperkeeper_ is running, point your browser to either http://localhost:8080/ernie or http://localhost:8080/bert to see the ring handlers and hit counter in action. As you can see from the command line there are two configuration files needed to launch _trapperkeeper_. ### The `bootstrap.cfg` file The bootstrap config file contains a list of services that _trapperkeeper_ will load up and make available. They are listed as fully-qualified Clojure namespaces and service names. For this example the bootstrap.cfg looks like this: ``` puppetlabs.trapperkeeper.services.webserver.jetty-service/jetty-service examples.ring-app.example-services/count-service examples.ring-app.example-services/bert-service examples.ring-app.example-services/ernie-service ``` This configuration indicates the jetty `WebserverService` is to be loaded, as well as the three new services defined in the `example_services.clj` file. ### The `ring-example.conf` configuration file For the application configuration, a file called `ring-example.conf` provides the most minimal configuration of the webserver-service, which is simply the port the service will be listening on and also a `logging-config` key which contains a path to a logback config file which defines the logging configuration. ``` global { # Points to a logback config file logging-config: examples/ring_app/logback.xml } webserver { # Port to listen on for clear-text HTTP. port: 8080 } ``` ### Debug mode There is a debugging statement inside the count-service which displays the state of the counter when it is to be incremented. To turn on debugging logging pass in the `--debug` option on the command line, like so: ```sh lein trampoline run --config examples/ring_app/ring-example.conf \ --bootstrap-config examples/ring_app/bootstrap.cfg \ --debug ``` When run you will see debug output any time you hit the hit-counting endpoint. This is the equivalent of setting the logback root logger to `DEBUG` instead of `INFO`, and will override whatever log level the root logger is set to. ## Defining the Services And now, without further ado, let's look at some code! ### Define the _hit count_ service First we will need to define the hit counter service, which will later be used by the web services to show users which visitor number they are. It is entirely expressed with this code: ```clj (def ^{:private true} hit-count (atom {})) (defn- inc-and-get "Increments the hit count for the provided endpoint and returns the new hit count." [endpoint] {:pre [(string? endpoint)] :post [(integer? %) (> % 0)]} (let [new-hit-counts (swap! hit-count #(assoc % endpoint (cond (contains? % endpoint) (inc (% endpoint)) :else 1)))] (log/debug "Incrementing hit count for" endpoint "from" (dec (new-hit-counts endpoint)) "to" (new-hit-counts endpoint)) (new-hit-counts endpoint))) (defprotocol CountService (inc-and-get [this endpoint])) (defservice count-service "This is a simple service which simply keeps a counter. It contains one function, inc-and-get, which increments the count and returns it." ;; Here we specify the service's protocol CountService ;; This vector declares the service's dependencies on other services and their functions, [] ;; Implement the `init` function from the `Lifecycle` protocol to ;; initialize state: (init [this context] (assoc context :hit-counts (atom {}))) ;; Implement the inc-and-get function. (inc-and-get [this endpoint] (inc-and-get* ((service-context this) :hit-counts) endpoint))) ``` The `defservice` macro is used to define a _trapperkeeper_ service and it is located in the `puppetlabs._trapperkeeper_.core` namespace. For more info on how the `defservice` macro works, see the [`defservice` section of the trapperkeeper docs](https://github.com/puppetlabs/trapperkeeper/tree/0.3.0#defservice) The `inc-and-get` function will keep a tally of hit counts for a provided endpoint. It is later exported with the last form in the service definition which is a map of this service's function names to the actual functions which do all the work. ### Define the _bert_ service The `bert-service` is a more interesting service which utilizes the `webserver` service to create HTTP responses to requests made to specific endpoints, and is defined here: ```clj (defn- success-response "Return a ring response map containing a HTTP response code of 200 (OK) and HTML which displays the hitcount on this endpoint as well as all the data provided by Ring." [hit-count req] {:status 200 :body (str "

Hello from http://" (:server-name req) ":" (:server-port req) (:uri req) "

" (if (:debug? req) "

DEBUGGING ENABLED!

" "") "

You are visitor number " hit-count ".

" "
" (pprint-to-string req) "
")}) (defn- ring-handler "Executes the inc-and-get command and passes it into success-reponse which generates a ring response." [inc-and-get endpoint req] (success-response (inc-and-get endpoint) req)) (defservice bert-service "This is the bert web service. The Clojure web application library, Ring, is used to create simple responses to an endpoint. It depends on the count-service above to use as a primitive hit counter. See https://github.com/ring-clojure/ring for documentation on Ring." ;; This service needs functionality from the webserver service, and the count service. [[:WebserverService add-ring-handler] [:CountService inc-and-get]] ;; Implement the `init` lifecycle function to register the ring handler (init [this context] (let [endpoint "/bert"] (add-ring-handler (partial ring-handler inc-and-get endpoint) endpoint)) context) (stop [this context] (log/info "Bert service shutting down") context)) ``` The general structure of this service is similar to the _hit count_ service. Since this service requires the use of functionality from other services, the dependency list contains two dependent services and the functions that are required from each. The element containing `[:WebserverService add-ring-handler]` states that the `add-ring-handler` function from the `:WebserverService` is needed by this service. And, of course, we also need to pull in the `inc-and-get` function from the _hit count_ service previously defined. This is accomplished by the `[:CountService inc-and-get]` dependency list item. #### Ring handlers In the body of the service definition is a call to the `add-ring-handler` function. This function takes two parameters, the first being a _ring handler_ which is, essentially, a function which takes a `request` data map as a single parameter and returns a map containing different parts of an HTTP response. The second parameter to `add-ring-handler` is the base endpoint that the handler is attached to. In this example, a partial function is created from the `ring-handler` function which is passed an endpoint to operate on and the `inc-and-get` function from the _hit count_ service which generates the hit count. See https://github.com/ring-clojure/ring for further documentation on the Ring API. ### Define the _ernie_ service The _ernie_ service is very similar to the _bert_ service, but also leverages another bit of built-in _trapperkeeper_ functionality: the `:ConfigService`. This service can be specified as a dependency, and provides functions that can be used to retrieve user-specified configuration values. In this case, we've added an `example` section to the `ring-example.conf` file, and specified a setting `ernie-url-prefix` that can be used to control the URL prefix where the `ernie-service` will be available in the web server. The config service also provides a top-level config setting named `:debug`, which is a boolean that reflects whether or not the user launched _trapperkeeper_ in debug mode. In the `ernie-service` we use a simple ring middleware function to inject that value into the ring request map, so that it can be checked by the ring handler. ```clj (defn debug-middleware "Ring middleware to add the :debug configuration value to the request map." [app debug?] (fn [req] (app (assoc req :debug? debug?)))) (defservice ernie-service "This is the ernie service which operates on the /ernie endpoint. It is essentially identical to the bert service." [[:WebserverService add-ring-handler] [:CountService inc-and-get] [:ConfigService get-in-config]] (init [this context] (let [endpoint (get-in-config [:example :ernie-url-prefix]) ring-handler (-> (partial ring-handler inc-and-get endpoint) (debug-middleware (get-in-config [:debug])))] (add-ring-handler ring-handler endpoint)) context) (stop [this context] (log/info "Ernie service shutting down") context)) ``` This means that you can change the URL of the `ernie-service` simply by editing the configuration file. ## Logging At startup, _trapperkeeper_ will configure the logging system based on a logback configuration file. This means that your services can all just dive run it and call the logging functions available in `clojure.tools.logging` without worrying about configuration. ### The `logback.xml` file A minimal `logback.xml` file is provided in this example to demonstrate how to configure logging in _trapperkeeper_. ```xml %d %-5p [%c{2}] %m%n ``` See http://logback.qos.ch/manual/configuration.html for documentation on how to configure logback. OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/bootstrap.cfg000066400000000000000000000005721527232126200277730ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service puppetlabs.trapperkeeper.services.webserver.jetty-service/jetty-service puppetlabs.trapperkeeper.services.watcher.filesystem-watch-service/filesystem-watch-service examples.ring-app.example-services/count-service examples.ring-app.example-services/bert-service examples.ring-app.example-services/ernie-service OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/logback.xml000066400000000000000000000004511527232126200274150ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/ring-example.conf000066400000000000000000000005211527232126200305260ustar00rootroot00000000000000global: { # Points to a logback config file logging-config: examples/ring_app/logback.xml } nrepl: { enabled: true } webserver: { # Port to listen on for clear-text HTTP. port: 8080 } example: { # The URL prefix at which the ernie service should be available in the web server. ernie-url-prefix: /ernie } OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/src/000077500000000000000000000000001527232126200260605ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/src/examples/000077500000000000000000000000001527232126200276765ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/src/examples/ring_app/000077500000000000000000000000001527232126200314755ustar00rootroot00000000000000example_services.clj000066400000000000000000000072631527232126200354560ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/src/examples/ring_app(ns examples.ring-app.example-services (:import (clojure.lang Atom)) (:require [clojure.tools.logging :as log] [puppetlabs.kitchensink.core :refer [pprint-to-string]] [puppetlabs.trapperkeeper.core :refer [defservice]] [puppetlabs.trapperkeeper.services :refer [service-context]])) (defn- inc-and-get* "Increments the hit count for the provided endpoint and returns the new hit count." [hit-counts endpoint] {:pre [(instance? Atom hit-counts) (string? endpoint)] :post [(integer? %) (> % 0)]} (let [new-hit-counts (swap! hit-counts update-in [endpoint] (fnil inc 0))] (log/debug "Incrementing hit count for" endpoint "from" (dec (new-hit-counts endpoint)) "to" (new-hit-counts endpoint)) (new-hit-counts endpoint))) (defprotocol CountService (inc-and-get [this endpoint])) (defservice count-service "This is a simple service which simply keeps a counter. It contains one function, inc-and-get, which increments the count and returns it." ;; Here we specify the service's protocol CountService ;; This vector declares the service's dependencies on other services and their functions, [] ;; Implement the `init` function from the `Lifecycle` protocol to ;; initialize state: (init [this context] (assoc context :hit-counts (atom {}))) ;; Implement the inc-and-get function. (inc-and-get [this endpoint] (inc-and-get* ((service-context this) :hit-counts) endpoint))) (defn- success-response "Return a ring response map containing a HTTP response code of 200 (OK) and HTML which displays the hitcount on this endpoint as well as all the data provided by Ring." [hit-count req] {:status 200 :body (str "

Hello from http://" (:server-name req) ":" (:server-port req) (:uri req) "

" (if (:debug? req) "

DEBUGGING ENABLED!

" "") "

You are visitor number " hit-count ".

" "
" (pprint-to-string req) "
")}) (defn- ring-handler "Executes the inc-and-get command and passes it into success-reponse which generates a ring response." [inc-and-get endpoint req] (success-response (inc-and-get endpoint) req)) (defservice bert-service "This is the bert web service. The Clojure web application library, Ring, is used to create simple responses to an endpoint. It depends on the count-service above to use as a primitive hit counter. See https://github.com/ring-clojure/ring for documentation on Ring." ;; This service needs functionality from the webserver service, and the count service. [[:WebserverService add-ring-handler] [:CountService inc-and-get]] ;; Implement the `init` lifecycle function to register the ring handler (init [this context] (let [endpoint "/bert"] (add-ring-handler (partial ring-handler inc-and-get endpoint) endpoint)) context) (stop [this context] (log/info "Bert service shutting down") context)) (defn debug-middleware "Ring middleware to add the :debug configuration value to the request map." [app debug?] (fn [req] (app (assoc req :debug? debug?)))) (defservice ernie-service "This is the ernie service which operates on the /ernie endpoint. It is essentially identical to the bert service." [[:WebserverService add-ring-handler] [:CountService inc-and-get] [:ConfigService get-in-config]] (init [this context] (let [endpoint (get-in-config [:example :ernie-url-prefix]) ring-handler (-> (partial ring-handler inc-and-get endpoint) (debug-middleware (get-in-config [:debug])))] (add-ring-handler ring-handler endpoint)) context) (stop [this context] (log/info "Ernie service shutting down") context)) OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/ring_app/src/examples/ring_app/repl.clj000066400000000000000000000043311527232126200331320ustar00rootroot00000000000000(ns examples.ring-app.repl (:require [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service]] [examples.ring-app.example-services :refer [count-service bert-service ernie-service]] [puppetlabs.trapperkeeper.core :as tk] [puppetlabs.trapperkeeper.app :as tka] [clojure.tools.namespace.repl :refer (refresh)])) ;; This namespace shows an example of the "reloaded" clojure workflow ;; ( http://thinkrelevance.com/blog/2013/06/04/clojure-workflow-reloaded ) ;; ;; It's based on the pattern from Stuart Sierra's `Component` library: ;; ( https://github.com/stuartsierra/component#reloading ) ;; ;; You can load this namespace up into a REPL and then run `(go)` to boot ;; and run the sample application. Then, you can run `(reset)` at any time ;; to stop the running app, reload all of the necessary namespaces, and start ;; a new instance of the app. This means that you can do iterative development ;; without having to restart the whole JVM. ;; ;; You can also view the context of the application (and all of the ;; trapperkeeper services) via `(context)` (or pretty-printed with ;; `print-context`). (def system nil) (defn init [] (alter-var-root #'system (fn [_] (tk/build-app [jetty-service count-service bert-service ernie-service] {:global {:logging-config "examples/ring_app/logback.xml"} :webserver {:port 8080 } :example {:ernie-url-prefix "/ernie"}}))) (alter-var-root #'system tka/init) (tka/check-for-errors! system)) (defn start [] (alter-var-root #'system (fn [s] (if s (tka/start s)))) (tka/check-for-errors! system)) (defn stop [] (alter-var-root #'system (fn [s] (if s (tka/stop s))))) (defn go [] (init) (start)) (defn context [] @(tka/app-context system)) (defn print-context [] (clojure.pprint/pprint (context))) (defn reset [] (stop) (refresh :after 'examples.ring-app.repl/go)) OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/000077500000000000000000000000001527232126200260165ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/README.md000066400000000000000000000004111527232126200272710ustar00rootroot00000000000000Sample Trapperkeeper Servlet Web App --------------------------------- To run the app, use this command: ```sh lein trampoline run --config examples/servlet_app/servlet-example.conf \ --bootstrap-config examples/servlet_app/bootstrap.cfg ``` OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/bootstrap.cfg000066400000000000000000000001771527232126200305210ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.webserver.jetty-service/jetty-service examples.servlet-app.servlet-app/hello-servlet-service OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/logback.xml000066400000000000000000000004511527232126200301420ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/servlet-example.conf000066400000000000000000000002301527232126200317750ustar00rootroot00000000000000global: { # Points to a logback config file logging-config: examples/servlet_app/logback.xml } webserver: { host: 0.0.0.0 port: 8080 } OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/000077500000000000000000000000001527232126200266055ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/clj/000077500000000000000000000000001527232126200273555ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/clj/examples/000077500000000000000000000000001527232126200311735ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/clj/examples/servlet_app/000077500000000000000000000000001527232126200335175ustar00rootroot00000000000000servlet_app.clj000066400000000000000000000011321527232126200364530ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/clj/examples/servlet_app(ns examples.servlet-app.servlet-app (:import [examples.servlet_app MyServlet]) (:require [puppetlabs.trapperkeeper.core :refer [defservice]] [clojure.tools.logging :as log])) (defservice hello-servlet-service [[:WebserverService add-servlet-handler]] (init [this context] (log/info "Initializing hello-servlet-service") (add-servlet-handler (MyServlet. "Hi there!") "/hello") (add-servlet-handler (MyServlet. "See you later!") "/goodbye") context) (stop [this context] (log/info "Shutting down hello-servlet-service") context)) OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/java/000077500000000000000000000000001527232126200275265ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/java/examples/000077500000000000000000000000001527232126200313445ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/java/examples/servlet_app/000077500000000000000000000000001527232126200336705ustar00rootroot00000000000000MyServlet.java000066400000000000000000000012171527232126200364070ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/servlet_app/src/java/examples/servlet_apppackage examples.servlet_app; import java.io.IOException; import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class MyServlet extends HttpServlet { private String message; public MyServlet(String message) { this.message = message; } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); response.getWriter().println(message); } } OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/000077500000000000000000000000001527232126200251235ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/README.md000066400000000000000000000005411527232126200264020ustar00rootroot00000000000000Sample Trapperkeeper WAR Web App --------------------------------- To run the app, use this command: ```sh lein trampoline run --config examples/war_app/war-example.conf \ --bootstrap-config examples/war_app/bootstrap.cfg ``` Open ``` http://localhost:8080/test/hello ``` in your browser to see the famous Hello World message.OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/bootstrap.cfg000066400000000000000000000001621527232126200276200ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.webserver.jetty-service/jetty-service examples.war-app.war-app/hello-webservice OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/logback.xml000066400000000000000000000004511527232126200272470ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/src/000077500000000000000000000000001527232126200257125ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/src/examples/000077500000000000000000000000001527232126200275305ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/src/examples/war_app/000077500000000000000000000000001527232126200311615ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/src/examples/war_app/war_app.clj000066400000000000000000000007131527232126200333050ustar00rootroot00000000000000(ns examples.war-app.war-app (:require [puppetlabs.trapperkeeper.core :refer [defservice]] [clojure.tools.logging :as log])) (defservice hello-webservice [[:WebserverService add-war-handler]] (init [this context] (log/info "Initializing hello web service") (add-war-handler "dev-resources/helloWorld.war" "/test") context) (stop [this context] (log/info "Shutting down hello web service") context))OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/war_app/war-example.conf000066400000000000000000000002321527232126200302110ustar00rootroot00000000000000global: { # Points to a logback configuration file logging-config: examples/war_app/logback.xml } webserver: { host: 0.0.0.0 port: 8080 }OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/000077500000000000000000000000001527232126200265175ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/README.md000066400000000000000000000012431527232126200277760ustar00rootroot00000000000000Sample Trapperkeeper Multiserver Web App ----------------------------------------- To run the app, use this command: ```sh lein trampoline run --config examples/webrouting_app/webrouting-example.conf \ --bootstrap-config examples/webrouting_app/bootstrap.cfg ``` Open any of ``` http://localhost:8080/foo http://localhost:8080/bar http://localhost:8080/baz http://localhost:8080/goodbye http://localhost:9000/quux http://localhost:9000/bert ``` in your browser to see the famous Hello World message. Open ``` http://localhost:8080/hello/[string] ``` where [string] is any string of your choosing to see a Hello message specific for that string. OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/bootstrap.cfg000066400000000000000000000007541527232126200312230ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service puppetlabs.trapperkeeper.services.webserver.jetty-service/jetty-service puppetlabs.trapperkeeper.services.webrouting.webrouting-service/webrouting-service examples.webrouting-app.example-services/foo-service examples.webrouting-app.example-services/bar-service examples.webrouting-app.example-services/quux-service examples.webrouting-app.example-services/bert-service examples.webrouting-app.example-services/hello-service OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/logback.xml000066400000000000000000000004511527232126200306430ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/src/000077500000000000000000000000001527232126200273065ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/src/examples/000077500000000000000000000000001527232126200311245ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/src/examples/webrouting_app/000077500000000000000000000000001527232126200341515ustar00rootroot00000000000000example_services.clj000066400000000000000000000036471527232126200401340ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/src/examples/webrouting_app(ns examples.webrouting-app.example-services (:require [clojure.tools.logging :as log] [puppetlabs.trapperkeeper.core :refer [defservice]] [puppetlabs.trapperkeeper.services :refer [get-services]] [compojure.core :as compojure] [compojure.route :as route])) (defn hello-world-app [req] {:status 200 :headers {"Content-Type" "text/plain"} :body "Hello, World!"}) (defn hello-app [] (compojure/routes (compojure/GET "/:caller" [caller] (fn [req] (log/info "Handling request for caller:" caller) {:status 200 :headers {"Content-Type" "text/plain"} :body (format "Hello, %s!" caller)})) (route/not-found "Not Found"))) (defservice foo-service [[:WebroutingService add-ring-handler]] (init [this context] (log/info "Initializing foo service") (add-ring-handler this hello-world-app) context)) (defservice bar-service [[:WebroutingService add-ring-handler]] (init [this context] (log/info "Initializing bar service") (add-ring-handler this hello-world-app {:route-id :bar}) (add-ring-handler this hello-world-app {:route-id :baz}) context)) (defservice quux-service [[:WebroutingService add-ring-handler]] (init [this context] (log/info "Initializing quux service") (add-ring-handler this hello-world-app) context)) (defservice bert-service [[:WebroutingService add-ring-handler]] (init [this context] (log/info "Initializing bert service") (add-ring-handler this hello-world-app {:route-id :baz}) (add-ring-handler this hello-world-app {:route-id :bert}) context)) (defservice hello-service [[:WebroutingService add-ring-handler get-route]] (init [this context] (log/info "Initializing hello service") (let [url-prefix (get-route this)] (add-ring-handler this (compojure/context url-prefix [] (hello-app)))) context))OpenVoxProject-trapperkeeper-webserver-8a905f4/examples/webrouting_app/webrouting-example.conf000066400000000000000000000014571527232126200332130ustar00rootroot00000000000000global: { # Points to a logback config file logging-config: examples/webrouting_app/logback.xml } nrepl: { enabled: true } webserver: { foo: { port: 8080 default-server: true } quux: { port: 9000 } } web-router-service: { "examples.webrouting-app.example-services/foo-service": "/foo" "examples.webrouting-app.example-services/bar-service": { bar: "/bar" baz: "/goodbye" } "examples.webrouting-app.example-services/quux-service": { route: "/quux" server: "quux" } "examples.webrouting-app.example-services/bert-service": { baz: "/baz" bert: { route: "/bert" server: "quux" } } "examples.webrouting-app.example-services/hello-service": "/hello" } OpenVoxProject-trapperkeeper-webserver-8a905f4/java/000077500000000000000000000000001527232126200225755ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/000077500000000000000000000000001527232126200233535ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/000077500000000000000000000000001527232126200255325ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/000077500000000000000000000000001527232126200304035ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/000077500000000000000000000000001527232126200322265ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/000077500000000000000000000000001527232126200342325ustar00rootroot00000000000000jetty/000077500000000000000000000000001527232126200353125ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserverutils/000077500000000000000000000000001527232126200364525ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/jettyHttpServletRequestWithAlternateRequestUri.java000066400000000000000000000014771527232126200477100ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/jetty/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty.utils; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequestWrapper; /** * This class provides a wrapper for an existing HttpServletRequest object * which returns an alternate request URI from the one that the injected * HttpServletRequest object would return when its getRequestURI() method * is called. */ public class HttpServletRequestWithAlternateRequestUri extends HttpServletRequestWrapper { private String requestUri; public HttpServletRequestWithAlternateRequestUri( HttpServletRequest request, String requestUri) { super(request); this.requestUri = requestUri; } @Override public String getRequestURI() { return requestUri; } } InternalSslContextFactory.java000066400000000000000000000056031527232126200444540ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/jetty/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty.utils; import org.eclipse.jetty.util.security.CertificateUtils; import org.eclipse.jetty.util.ssl.SslContextFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.security.cert.CRL; import java.util.Collection; import java.util.function.Consumer; public class InternalSslContextFactory extends SslContextFactory.Server { private static int maxTries = 25; private static int sleepInMillisecondsBetweenTries = 100; private static final Logger LOG = LoggerFactory.getLogger(InternalSslContextFactory.class); private static Consumer consumer = sslContextFactory -> {}; private Collection _crls; @Override protected Collection loadCRL(String crlPath) throws Exception { Collection crls; synchronized (this) { if (_crls == null) { crls = super.loadCRL(crlPath); } else { crls = _crls; } } return crls; } public void reload() throws Exception { synchronized (this) { Exception reloadEx = null; int tries = maxTries; String crlPath = getCrlPath(); if (crlPath != null) { File crlPathAsFile = new File(crlPath); long crlLastModified = crlPathAsFile.lastModified(); // Try to parse CRLs from the crlPath until it is successful // or a hard-coded number of failed attempts have been made. do { reloadEx = null; try { _crls = CertificateUtils.loadCRL(crlPath); } catch (Exception e) { reloadEx = e; // If the CRL file has been updated since the last reload // attempt, reset the retry counter. if (crlPathAsFile != null && crlLastModified != crlPathAsFile.lastModified()) { crlLastModified = crlPathAsFile.lastModified(); tries = maxTries; } else { tries--; } if (tries == 0) { LOG.warn("Failed ssl context reload after " + maxTries + " tries. CRL file is: " + crlPath, reloadEx); } else { Thread.sleep(sleepInMillisecondsBetweenTries); } } } while (reloadEx != null && tries > 0); } if (reloadEx == null) { reload(consumer); } } } } MDCAccessLogConverter.java000066400000000000000000000055301527232126200433770ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/jetty/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty.utils; import java.util.Map; import jakarta.servlet.http.HttpServletRequest; import ch.qos.logback.core.util.OptionHelper; import ch.qos.logback.access.common.pattern.AccessConverter; import ch.qos.logback.access.common.spi.IAccessEvent; /** * A Logback pattern converter for logback-access that provides access to * items in the SLF4J Mapped Diagnostic Context (MDC). * * This implementation is adapted from the MDCConverter in logback-classic, * with the modification that MDC data is pulled directly from SLF4J rather * than from the log event object as IAccessEvent has no accessor method for * the MDC at this time. The TrapperKeeper framework configures SLF4J as the * logging interface, so we don't need to worry about abstracting over multiple * backends to the same degree that logback-access does. * * This class may be removable if MDC support lands upstream in logback-access: * * https://jira.qos.ch/browse/LOGBACK-1016 * https://github.com/qos-ch/logback/pull/359 */ public class MDCAccessLogConverter extends AccessConverter { private String key; private String defaultValue = ""; @Override public void start() { String[] keyInfo = OptionHelper.extractDefaultReplacement(getFirstOption()); key = keyInfo[0]; if (keyInfo[1] != null) { defaultValue = keyInfo[1]; } super.start(); } @Override public void stop() { key = null; defaultValue = ""; super.stop(); } @Override public String convert(IAccessEvent accessEvent) { Map mdcPropertyMap = null; HttpServletRequest request = accessEvent.getRequest(); if (request != null) { mdcPropertyMap = extractMdcFromRequest(request); } if (mdcPropertyMap == null) { return defaultValue; } if (key == null) { return outputMDCForAllKeys(mdcPropertyMap); } else { String value = mdcPropertyMap.get(key); if (value != null) { return value; } else { return defaultValue; } } } private String outputMDCForAllKeys(Map mdcPropertyMap) { StringBuilder buf = new StringBuilder(); boolean first = true; for (Map.Entry entry : mdcPropertyMap.entrySet()) { if (first) { first = false; } else { buf.append(", "); } // format: key0=value0, key1=value1 buf.append(entry.getKey()).append('=').append(entry.getValue()); } return buf.toString(); } private Map extractMdcFromRequest(HttpServletRequest request) { // Will either be null or a Map stored by an instance of // the MDCHandler class. @SuppressWarnings("unchecked") Map result = (Map) request.getAttribute(MDCHandler.MDC_ATTR); return result; } } MDCHandler.java000066400000000000000000000060731527232126200412240ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/jetty/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty.utils; import java.util.Map; import org.eclipse.jetty.server.Handler; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import org.eclipse.jetty.util.Callback; import org.slf4j.MDC; /** * A Jetty 12 Handler.Wrapper implementation that imbues Request objects * with a copy of the SLF4J Mapped Diagnostic Context (MDC) and handles clearing * the MDC after each request. * * In Jetty 12, RequestLogHandler was removed. This replaces MDCRequestLogHandler * from Jetty 10 with the new Handler.Wrapper pattern. * * The MDC is captured after the wrapped handler completes (but before the * response callback finishes), ensuring that any MDC values set during request * handling are available to the access logger. * * Patterned after: * https://github.com/jetty-project/jetty-and-logback-example/blob/master/jetty-slf4j-mdc-handler/src/main/java/org/eclipse/jetty/examples/logging/MDCHandler.java */ public class MDCHandler extends Handler.Wrapper { public static final String MDC_ATTR = "com.puppetlabs.trapperkeeper.services.webserver.jetty12.MDC"; public MDCHandler(Handler handler) { super(handler); } @Override public boolean handle(Request request, Response response, Callback callback) throws Exception { // Save any existing MDC context to restore after the request Map savedContext = MDC.getCopyOfContextMap(); // Wrap the callback to capture MDC after handler completes Callback wrappedCallback = new Callback() { @Override public void succeeded() { try { // Capture MDC after handler has run but before response completes // This ensures MDC values set during request handling are available Map mdcPropertyMap = MDC.getCopyOfContextMap(); request.setAttribute(MDC_ATTR, mdcPropertyMap); } finally { // Clean up MDC for this thread to prevent contamination if (savedContext != null) { MDC.setContextMap(savedContext); } else { MDC.clear(); } } callback.succeeded(); } @Override public void failed(Throwable x) { try { // Still capture MDC on failure for logging purposes Map mdcPropertyMap = MDC.getCopyOfContextMap(); request.setAttribute(MDC_ATTR, mdcPropertyMap); } finally { // Clean up MDC for this thread if (savedContext != null) { MDC.setContextMap(savedContext); } else { MDC.clear(); } } callback.failed(x); } }; return super.handle(request, response, wrappedCallback); } } ModifiedJettyModernServerAdapter.java000066400000000000000000000027071527232126200457200ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/jetty/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty.utils; import ch.qos.logback.access.jetty.JettyServerAdapter; import org.eclipse.jetty.http.HttpField; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import java.util.HashMap; import java.util.Map; /** * Custom JettyServerAdapter for Jetty 12 compatibility. * This may not be needed with logback-access-jetty12 but is kept for compatibility. */ public class ModifiedJettyModernServerAdapter extends JettyServerAdapter { // these are package private in the JettyServerAdapter, unfortunately Request request; Response response; public ModifiedJettyModernServerAdapter(Request jettyRequest, Response jettyResponse) { super(jettyRequest, jettyResponse); this.response = jettyResponse; this.request = jettyRequest; } /** * buildResponseMap * This is a replacement of the buildResponseLog in JettyServerAdapter to * make it compatible with Jetty 12 responses. * @return a map of the headers. */ @Override public Map buildResponseHeaderMap() { Map responseHeaderMap = new HashMap(); for (HttpField httpField : this.response.getHeaders()) { String key = httpField.getName(); String value = httpField.getValue(); responseHeaderMap.put(key, value); } return responseHeaderMap; } } ModifiedRequestLogImpl.java000066400000000000000000000066201527232126200436760ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/java/com/puppetlabs/trapperkeeper/services/webserver/jetty/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty.utils; import ch.qos.logback.access.jetty.JettyServerAdapter; import ch.qos.logback.access.jetty.RequestLogImpl; import ch.qos.logback.access.jetty.RequestWrapper; import ch.qos.logback.access.jetty.ResponseWrapper; import ch.qos.logback.access.common.spi.AccessEvent; import ch.qos.logback.access.common.spi.IAccessEvent; import ch.qos.logback.core.Appender; import ch.qos.logback.core.spi.AppenderAttachableImpl; import ch.qos.logback.core.spi.FilterReply; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.Response; import java.util.Iterator; /** * Provide an alternative RequestLogImpl implementation that is compatible with Jetty 12. * Uses RequestWrapper and ResponseWrapper to convert core Jetty types to servlet types. */ public class ModifiedRequestLogImpl extends RequestLogImpl { // unfortunately, this field is private in RequestLogImpl, so we provide our own version of it, and recreate // all the functions in the RequestLogImpl that use it AppenderAttachableImpl aai = new AppenderAttachableImpl(); /** * log - override the log funciton in RequestLogImpl for the sole purpose of changing the type of the `makeJettyServerAdapter` * to make it compatible with jetty. * @param jettyRequest * @param jettyResponse */ @Override public void log(Request jettyRequest, Response jettyResponse) { JettyServerAdapter adapter = this.makeJettyServerAdapter(jettyRequest, jettyResponse); // Wrap core Jetty types in servlet wrappers for AccessEvent RequestWrapper requestWrapper = new RequestWrapper(jettyRequest); ResponseWrapper responseWrapper = new ResponseWrapper(jettyResponse); IAccessEvent accessEvent = new AccessEvent(this, requestWrapper, responseWrapper, adapter); if (this.getFilterChainDecision(accessEvent) != FilterReply.DENY) { this.aai.appendLoopOnAppenders(accessEvent); } } /** * Provide a new JettyServerAdapter that is compatible with Jetty 12. * @param jettyRequest the Jetty 12 core Request * @param jettyResponse the Jetty 12 core Response * @return a JettyServerAdapter for the request/response pair */ private JettyServerAdapter makeJettyServerAdapter(Request jettyRequest, Response jettyResponse) { return new ModifiedJettyModernServerAdapter(jettyRequest, jettyResponse); } @Override public void stop() { this.aai.detachAndStopAllAppenders(); super.stop(); } @Override public void addAppender(Appender newAppender) { aai.addAppender(newAppender); } @Override public Iterator> iteratorForAppenders() { return aai.iteratorForAppenders(); } @Override public Appender getAppender(String name) { return aai.getAppender(name); } @Override public boolean isAttached(Appender appender) { return aai.isAttached(appender); } @Override public void detachAndStopAllAppenders() { aai.detachAndStopAllAppenders(); } @Override public boolean detachAppender(Appender appender) { return aai.detachAppender(appender); } @Override public boolean detachAppender(String name) { return aai.detachAppender(name); } } OpenVoxProject-trapperkeeper-webserver-8a905f4/locales/000077500000000000000000000000001527232126200232765ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/locales/eo.po000066400000000000000000000132571527232126200242510ustar00rootroot00000000000000# Esperanto translations for puppetlabs.trapperkeeper_webserver package. # Copyright (C) 2017 Puppet # This file is distributed under the same license as the puppetlabs.trapperkeeper_webserver package. # Automatically generated, 2017. # msgid "" msgstr "" "Project-Id-Version: puppetlabs.trapperkeeper_webserver \n" "Report-Msgid-Bugs-To: docs@puppet.com\n" "POT-Creation-Date: \n" "PO-Revision-Date: \n" "Last-Translator: Automatically generated\n" "Language-Team: none\n" "Language: eo\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: src/puppetlabs/trapperkeeper/services/webrouting/webrouting_service_core.clj msgid "service {0} does not appear in configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webrouting/webrouting_service_core.clj msgid "endpoint with id {0} does not appear in configuration for service {1}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webrouting/webrouting_service_core.clj msgid "no route-id specified for a service with multiple routes" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/experimental/jetty_websockets.clj msgid "No handler defined for websocket event ''{0}'' with args: ''{1}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Found SSL config options: {0}; If configuring SSL from PEM files, you must " "provide all of the following options: {1}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Unable to open ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "No certs found in ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Unable to open ''ssl-cert-chain'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Found settings for both keystore-based and PEM-based SSL; using PEM-based " "settings, ignoring {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Missing some SSL configuration; must provide either :ssl-cert, :ssl-key, " "and :ssl-ca-cert, OR :truststore, :trust-password, :keystore, and :key-" "password." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Unexpected value found for client auth config option: {0}. Expected need, " "want, or none." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Non-readable path specified for ssl-crl-path option: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Error: More than one default server specified in configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Either host, port, ssl-host, or ssl-port must be specified on the config in " "order for the server to be started" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Removing buggy security provider {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Could not remove security providers; HTTPS may not work!" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "webserver config overridden for key ''{0}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "`ssl-protocols` contains SSLv3, a protocol with known vulnerabilities; we " "recommend removing it from the `ssl-protocols` list" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "{0} proxying failed" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "{0} could not close the connection" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Cleaning up JMX MBean container" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Shutting down web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "Web server failed to shut down gracefully in configured timeout period " "({0}); cancelling remaining requests." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Web server shutdown" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Starting web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Encountered error starting web server, so shutting down" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "overrides cannot be set because webserver has already processed the config" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "overrides cannot be set because they have already been set and webserver has " "already processed the config" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "overrides cannot be set because they have already been set" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "no server-id was specified for this operation and no default server was " "specified in the configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Initializing web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Starting web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Shutting down web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/normalized_uri_helpers.clj msgid "Invalid relative path (.. or .) in: {0}" msgstr "" OpenVoxProject-trapperkeeper-webserver-8a905f4/locales/trapperkeeper-webserver.pot000066400000000000000000000213001527232126200306710ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Puppet # This file is distributed under the same license as the com.puppetlabs.trapperkeeper_webserver package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: com.puppetlabs.trapperkeeper_webserver \n" "X-Git-Ref: b00ec1706f2899730603212d7820da788ff22165\n" "Report-Msgid-Bugs-To: docs@puppet.com\n" "POT-Creation-Date: \n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" "Language: \n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: src/puppetlabs/trapperkeeper/services/webrouting/webrouting_service_core.clj msgid "service {0} does not appear in configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webrouting/webrouting_service_core.clj msgid "endpoint with id {0} does not appear in configuration for service {1}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webrouting/webrouting_service_core.clj msgid "no route-id specified for a service with multiple routes" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "The so-linger-seconds setting was found to cause undefined behavior and was " "removed. The current value will be ignored." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Found SSL config options: {0}; If configuring SSL from PEM files, you must " "provide all of the following options: {1}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Unable to open ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "No certs found in ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Unable to open ''ssl-cert-chain'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Found settings for both keystore-based and PEM-based SSL; using PEM-based " "settings, ignoring {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Missing some SSL configuration; must provide either :ssl-cert, :ssl-key, " "and :ssl-ca-cert, OR :truststore, :trust-password, :keystore, and :key-" "password." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Unexpected value found for client auth config option: {0}. Expected need, " "want, or none." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Non-readable path specified for ssl-crl-path option: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Error: More than one default server specified in configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "" "Either host, port, ssl-host, or ssl-port must be specified on the config in " "order for the server to be started" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Found access-log file at {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Enabling access logger using file {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Access logging file not found at {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_config.clj msgid "Access log configuration not specified" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Removing buggy security provider {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Could not remove security providers; HTTPS may not work!" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "logging-router.properties not found, extra logging will occur" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "webserver config overridden for key ''{0}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "`ssl-protocols` contains SSLv3, a protocol with known vulnerabilities; " "ignoring" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "When `ssl-protocols` is empty, a default of {0} is assumed" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Proxy not configured with custom ssl, using server default" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Proxy Using same config as server for ssl in proxy" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Proxy using default http client with no SSL specification." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Cleaning up JMX MBean container" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Shutting down web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "Web server failed to shut down gracefully in configured timeout period " "({0}); cancelling remaining requests." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "Web server failed to shut down gracefully due to ExecutionException with " "inner exception of type {0}; cancelling remaining requests." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Web server shutdown" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Using specified access logging" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Using CustomRequestLog using extended NCSA format" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Server shutdown timeout set to {0} milliseconds" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Starting web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Encountered error starting web server, so shutting down" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "overrides cannot be set because webserver has already processed the config" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "overrides cannot be set because they have already been set and webserver has " "already processed the config" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "overrides cannot be set because they have already been set" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "" "no server-id was specified for this operation and no default server was " "specified in the configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "Setting up file watcher on {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_core.clj msgid "CRL reload triggered" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Initializing web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Starting web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Jetty server(s) starting with config: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Jetty server {0} started with context: {1}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Jetty server {0} started with URI: {1} Stop timeout: {2} milliseconds." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Jetty server {0} started with connector {1} with idle-timeout {2}." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Jetty server {0} started with connector {1} protocols: {2}." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_service.clj msgid "Shutting down web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_websockets.clj msgid "No handler defined for websocket event ''{0}'' with args: ''{1}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_websockets.clj msgid "" "Timed out after awaiting closure of websocket from remote for {0} seconds at " "request path {1}." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty_websockets.clj msgid "" "Thread was interrupted when awaiting closure of websocket from remote at " "request path {0}." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/normalized_uri_helpers.clj msgid "Invalid relative path (.. or .) in: {0}" msgstr "" OpenVoxProject-trapperkeeper-webserver-8a905f4/project.clj000066400000000000000000000216021527232126200240150ustar00rootroot00000000000000(def i18n-version "1.0.6") (def jetty-version "12.1.14") (def logback-version "1.6.6") (def slf4j-version "2.0.20") (defproject org.openvoxproject/trapperkeeper-webserver "12.2.0" :description "A jetty-based webserver implementation for use with the org.openvoxproject/trapperkeeper service framework." :url "https://github.com/openvoxproject/trapperkeeper-webserver" :license {:name "Apache License, Version 2.0" :url "http://www.apache.org/licenses/LICENSE-2.0"} :min-lein-version "2.12.0" ;; Abort when version ranges or version conflicts are detected in ;; dependencies. Also supports :warn to simply emit warnings. ;; requires lein 2.2.0+. :pedantic? :abort ;; Generally, try to keep version pins in :managed-dependencies and the libraries ;; this project actually uses in :dependencies, inheriting the version from ;; :managed-dependencies. This prevents endless version conflicts due to deps of deps. ;; Renovate should keep the versions largely in sync between projects. :managed-dependencies [[org.clojure/clojure "1.12.6"] [org.clojure/java.jmx "1.1.1"] [org.clojure/tools.logging "1.3.1"] [org.clojure/tools.namespace "0.3.1"] [org.clojure/tools.reader "1.6.0"] [org.clojure/tools.macro "0.2.2"] ;; Jetty Webserver (12.x with ee10 modules for Jakarta EE 10) [jakarta.servlet/jakarta.servlet-api "6.1.0"] [org.eclipse.jetty/jetty-server ~jetty-version] [org.eclipse.jetty.ee10/jetty-ee10-servlet ~jetty-version] [org.eclipse.jetty.ee10/jetty-ee10-servlets ~jetty-version] [org.eclipse.jetty.ee10/jetty-ee10-webapp ~jetty-version] [org.eclipse.jetty.ee10/jetty-ee10-proxy ~jetty-version] [org.eclipse.jetty/jetty-jmx ~jetty-version] [ch.qos.logback.access/logback-access-common "2.0.15"] [ch.qos.logback.access/logback-access-jetty12 "2.0.15"] [ch.qos.logback/logback-classic ~logback-version] [ch.qos.logback/logback-core ~logback-version] [clj-time "0.15.2"] [commons-codec "1.23.0"] [commons-io "2.22.0"] [compojure "1.7.2"] [javax.servlet/javax.servlet-api "4.0.1"] [org.bouncycastle/bcpkix-jdk18on "1.86"] [org.bouncycastle/bcpkix-fips "2.1.13"] [org.bouncycastle/bc-fips "2.1.3"] [org.bouncycastle/bctls-fips "2.1.25"] [org.bouncycastle/bcutil-fips "2.1.8"] [org.openvoxproject/http-client "2.4.1"] [org.openvoxproject/i18n ~i18n-version] [org.openvoxproject/kitchensink "3.5.8"] [org.openvoxproject/kitchensink "3.5.8" :classifier "test"] [org.openvoxproject/ssl-utils "3.7.1"] [org.openvoxproject/trapperkeeper "5.0.6"] [org.openvoxproject/trapperkeeper "5.0.6" :classifier "test"] [org.openvoxproject/trapperkeeper-filesystem-watcher "1.6.1"] [org.slf4j/jul-to-slf4j ~slf4j-version] [org.slf4j/log4j-over-slf4j ~slf4j-version] [org.slf4j/slf4j-api ~slf4j-version] [prismatic/schema "1.4.2"] [ring/ring-codec "1.3.0"] [ring/ring-core "1.15.6"] [org.ring-clojure/ring-jakarta-servlet "1.15.6"]] :dependencies [[org.clojure/clojure] [org.clojure/java.jmx] [org.clojure/tools.logging] ;; Jetty Webserver (12.x with ee10 modules for Jakarta EE 10) [jakarta.servlet/jakarta.servlet-api] [org.eclipse.jetty/jetty-server] [org.eclipse.jetty.ee10/jetty-ee10-servlet] [org.eclipse.jetty.ee10/jetty-ee10-servlets] [org.eclipse.jetty.ee10/jetty-ee10-webapp] [org.eclipse.jetty.ee10/jetty-ee10-proxy] [org.eclipse.jetty/jetty-jmx] [ch.qos.logback.access/logback-access-common] [ch.qos.logback.access/logback-access-jetty12] [ch.qos.logback/logback-classic] [ch.qos.logback/logback-core] [org.openvoxproject/i18n] [org.openvoxproject/kitchensink] [org.openvoxproject/ssl-utils] [org.openvoxproject/trapperkeeper] [org.openvoxproject/trapperkeeper-filesystem-watcher] [org.slf4j/jul-to-slf4j] [prismatic/schema] [ring/ring-codec] [org.ring-clojure/ring-jakarta-servlet]] :source-paths ["src"] :java-source-paths ["java"] :plugins [[org.openvoxproject/i18n ~i18n-version]] :deploy-repositories [["releases" {:url "https://clojars.org/repo" :username :env/CLOJARS_USERNAME :password :env/CLOJARS_PASSWORD :sign-releases false}]] ;; By declaring a classifier here and a corresponding profile below we'll get an additional jar ;; during `lein jar` that has all the code in the test/ directory. Downstream projects can then ;; depend on this test jar using a :classifier in their :dependencies to reuse the test utility ;; code that we have. :classifiers [["test" :testutils]] :test-paths ["test/clj"] :profiles {:shared {:source-paths ["examples/multiserver_app/src" "examples/ring_app/src" "examples/servlet_app/src/clj" "examples/war_app/src" "examples/webrouting_app/src"] :java-source-paths ["examples/servlet_app/src/java" "test/java"] :dependencies [[compojure] [org.clojure/tools.namespace] [org.openvoxproject/http-client] [org.openvoxproject/kitchensink :classifier "test"] [org.openvoxproject/trapperkeeper :classifier "test"] [ring/ring-core] ]} :dev-only {:dependencies [[org.bouncycastle/bcpkix-jdk18on]] :resource-paths ["dev-resources"] :jvm-opts ["-Djava.util.logging.config.file=dev-resources/logging.properties"]} :dev [:shared :dev-only] :fips-only {:dependencies [[org.bouncycastle/bcpkix-fips] [org.bouncycastle/bc-fips] [org.bouncycastle/bctls-fips] [org.bouncycastle/bcutil-fips]] ;; this only ensures that we run with the proper profiles ;; during testing. This JVM opt will be set in the puppet module ;; that sets up the JVM classpaths during installation. ;; Note: Jetty 12 requires Java 17+ :jvm-opts ~(let [version (System/getProperty "java.version") [major minor _] (clojure.string/split version #"\.") unsupported-ex (ex-info "Unsupported major Java version. Expects 17 or 21" {:major major :minor minor})] (condp = (java.lang.Integer/parseInt major) 17 ["-Djava.security.properties==dev-resources/jdk17-fips-security"] 21 ["-Djava.security.properties==dev-resources/jdk21-fips-security"] 25 ["-Djava.security.properties==dev-resources/jdk25-fips-security"] (throw unsupported-ex)))} :fips [:shared :fips-only] ;; per https://github.com/technomancy/leiningen/issues/1907 ;; the provided profile is necessary for lein jar / lein install :provided {:dependencies [[org.bouncycastle/bcpkix-jdk18on]]} :testutils {:source-paths ^:replace ["test/clj"] :java-source-paths ^:replace ["test/java"]}} :main puppetlabs.trapperkeeper.main) OpenVoxProject-trapperkeeper-webserver-8a905f4/renovate.json000066400000000000000000000006321527232126200243730ustar00rootroot00000000000000{ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "addLabels": ["renovate", "dependencies"], "assigneesFromCodeOwners": true, "automerge": true, "automergeType": "pr", "dependencyDashboard": true, "enabledManagers": ["leiningen"], "packageRules": [ { "matchPackageNames": ["org.eclipse.jetty*"], "matchUpdateTypes": ["major"], "enabled": false } ] } OpenVoxProject-trapperkeeper-webserver-8a905f4/resources/000077500000000000000000000000001527232126200236665ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/resources/logging-router.properties000066400000000000000000000003501527232126200307460ustar00rootroot00000000000000# register SLF4JBridgeHandler as handler for the j.u.l. root logger # bouncy castle FIPS is noisy via java.util.logging, let's force # it to go to slf4j handlers = org.slf4j.bridge.SLF4JBridgeHandler org.bouncycastle.level=WARNING OpenVoxProject-trapperkeeper-webserver-8a905f4/src/000077500000000000000000000000001527232126200224435ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/000077500000000000000000000000001527232126200246225ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/000077500000000000000000000000001527232126200274735ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/000077500000000000000000000000001527232126200313165ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webrouting/000077500000000000000000000000001527232126200335035ustar00rootroot00000000000000webrouting_service.clj000066400000000000000000000131571527232126200400320ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service (:require [puppetlabs.trapperkeeper.core :refer [defservice]] [puppetlabs.trapperkeeper.services :refer [service-context]] [puppetlabs.trapperkeeper.services.webrouting.webrouting-service-core :as core])) (defprotocol WebroutingService (get-route [this svc] [this svc route-id]) (get-server [this svc] [this svc route-id]) (add-context-handler [this svc context-path] [this svc context-path options]) (add-ring-handler [this svc handler] [this svc handler options]) (add-servlet-handler [this svc servlet] [this svc servlet options]) (add-war-handler [this svc war] [this svc war options]) (add-proxy-route [this svc target] [this svc target options]) (override-webserver-settings! [this overrides] [this server-id overrides]) (get-registered-endpoints [this] [this server-id]) (log-registered-endpoints [this] [this server-id]) (join [this] [this server-id])) (defservice webrouting-service "Provides the ability to route handlers to different jetty webserver services" WebroutingService [WebserverService [:ConfigService get-in-config]] (init [this context] (let [config (get-in-config [:web-router-service])] (when (nil? config) (throw (IllegalArgumentException. ":web-router-service section of configuration not present"))) (core/init context config))) (get-route [this svc] (core/get-route (service-context this) svc nil)) (get-route [this svc route-id] (core/get-route (service-context this) svc route-id)) (get-server [this svc] (core/get-server (service-context this) svc nil)) (get-server [this svc route-id] (core/get-server (service-context this) svc route-id)) (add-context-handler [this svc base-path] (core/add-context-handler! (service-context this) WebserverService svc base-path {})) (add-context-handler [this svc base-path options] (core/add-context-handler! (service-context this) WebserverService svc base-path options)) (add-ring-handler [this svc handler] (core/add-ring-handler! (service-context this) WebserverService svc handler {})) (add-ring-handler [this svc handler options] (core/add-ring-handler! (service-context this) WebserverService svc handler options)) (add-servlet-handler [this svc servlet] (core/add-servlet-handler! (service-context this) WebserverService svc servlet {})) (add-servlet-handler [this svc servlet options] (core/add-servlet-handler! (service-context this) WebserverService svc servlet options)) (add-war-handler [this svc war] (core/add-war-handler! (service-context this) WebserverService svc war {})) (add-war-handler [this svc war options] (core/add-war-handler! (service-context this) WebserverService svc war options)) (add-proxy-route [this svc target] (core/add-proxy-route! (service-context this) WebserverService svc target {})) (add-proxy-route [this svc target options] (core/add-proxy-route! (service-context this) WebserverService svc target options)) (override-webserver-settings! [this overrides] (let [override-webserver-settings (:override-webserver-settings! WebserverService)] (override-webserver-settings overrides))) (override-webserver-settings! [this server-id overrides] (let [override-webserver-settings (:override-webserver-settings! WebserverService)] (override-webserver-settings server-id overrides))) (get-registered-endpoints [this] (let [get-registered-endpoints (:get-registered-endpoints WebserverService)] (get-registered-endpoints))) (get-registered-endpoints [this server-id] (let [get-registered-endpoints (:get-registered-endpoints WebserverService)] (get-registered-endpoints server-id))) (log-registered-endpoints [this] (let [log-registered-endpoints (:log-registered-endpoints WebserverService)] (log-registered-endpoints))) (log-registered-endpoints [this server-id] (let [log-registered-endpoints (:log-registered-endpoints WebserverService)] (log-registered-endpoints server-id))) (join [this] (let [join (:join WebserverService)] (join))) (join [this server-id] (let [join (:join WebserverService)] (join server-id)))) webrouting_service_core.clj000066400000000000000000000145021527232126200410350ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-core (:require [puppetlabs.i18n.core :as i18n] [puppetlabs.trapperkeeper.services :as tk-services] [puppetlabs.trapperkeeper.services.webserver.jetty-core :as jetty-core] [schema.core :as schema])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Schemas (def RouteWithServerConfig {:route schema/Str :server schema/Str}) (def WebroutingMultipleConfig {schema/Keyword (schema/either schema/Str RouteWithServerConfig)}) (def WebroutingServiceConfig {schema/Keyword (schema/either schema/Str RouteWithServerConfig WebroutingMultipleConfig)}) (def RouteOption {(schema/optional-key :route-id) schema/Keyword}) (def CommonOptions (dissoc (merge jetty-core/CommonOptions RouteOption) :server-id)) (def ContextHandlerOptions (dissoc (merge jetty-core/ContextHandlerOptions RouteOption) :server-id)) (def ServletHandlerOptions (dissoc (merge jetty-core/ServletHandlerOptions RouteOption) :server-id)) (def ProxyRouteOptions (dissoc (merge jetty-core/ProxyOptions RouteOption) :server-id)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Private Utility Functions (defn get-endpoint-and-server-from-config [context svc route-id] (let [config (:web-router-service context) no-route-id? (nil? route-id) multi-route? (> (count (keys (get-in config [svc]))) 1) route-id (if no-route-id? :default route-id) endpoint (get-in config [svc route-id]) no-service? (nil? (get config svc)) no-endpoint? (nil? endpoint) no-server? (nil? (schema/check schema/Str endpoint)) server? (nil? (schema/check RouteWithServerConfig endpoint))] (cond no-service? (throw (IllegalArgumentException. (i18n/trs "service {0} does not appear in configuration" svc))) no-endpoint? (throw (IllegalArgumentException. (i18n/trs "endpoint with id {0} does not appear in configuration for service {1}" route-id svc))) (and no-route-id? multi-route?) (throw (IllegalArgumentException. (i18n/trs "no route-id specified for a service with multiple routes"))) no-server? {:route endpoint :server nil} server? endpoint))) (defn compute-common-elements [context svc options] (let [svc-id (keyword (tk-services/service-symbol svc)) route-id (:route-id options) route-and-server (get-endpoint-and-server-from-config context svc-id route-id) path (:route route-and-server) server (keyword (:server route-and-server)) options (dissoc options :route-id) opts (if (nil? server) options (assoc options :server-id server))] {:path path :opts opts})) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Lifecycle implementations (schema/defn ^:always-validate init [context config :- WebroutingServiceConfig] (let [configuration (into {} (for [[svc svc-config] config] (cond (nil? (schema/check (schema/either schema/Str RouteWithServerConfig) svc-config)) [svc {:default svc-config}] (nil? (schema/check WebroutingMultipleConfig svc-config)) [svc svc-config])))] (assoc context :web-router-service configuration))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Service function implementations (defn get-route [context svc route-id] (let [svc-id (keyword (tk-services/service-symbol svc)) endpoint-and-server (get-endpoint-and-server-from-config context svc-id route-id)] (:route endpoint-and-server))) (schema/defn ^:always-validate get-server :- (schema/maybe schema/Str) [context svc :- (schema/protocol tk-services/Service) route-id] (let [svc-id (keyword (tk-services/service-symbol svc)) endpoint-and-server (get-endpoint-and-server-from-config context svc-id route-id)] (:server endpoint-and-server))) (schema/defn ^:always-validate add-context-handler! [context webserver-service svc :- (schema/protocol tk-services/Service) base-path options :- ContextHandlerOptions] (let [{:keys [path opts]} (compute-common-elements context svc options) add-context-handler (:add-context-handler webserver-service)] (add-context-handler base-path path opts))) (schema/defn ^:always-validate add-ring-handler! [context webserver-service svc :- (schema/protocol tk-services/Service) handler options :- CommonOptions] (let [{:keys [path opts]} (compute-common-elements context svc options) add-ring-handler (:add-ring-handler webserver-service)] (add-ring-handler handler path opts))) (schema/defn ^:always-validate add-servlet-handler! [context webserver-service svc :- (schema/protocol tk-services/Service) servlet options :- ServletHandlerOptions] (let [{:keys [path opts]} (compute-common-elements context svc options) add-servlet-handler (:add-servlet-handler webserver-service)] (add-servlet-handler servlet path opts))) (schema/defn ^:always-validate add-war-handler! [context webserver-service svc :- (schema/protocol tk-services/Service) war options :- RouteOption] (let [{:keys [path opts]} (compute-common-elements context svc options) add-war-handler (:add-war-handler webserver-service)] (add-war-handler war path opts))) (schema/defn ^:always-validate add-proxy-route! [context webserver-service svc :- (schema/protocol tk-services/Service) target options :- ProxyRouteOptions] (let [{:keys [path opts]} (compute-common-elements context svc options) add-proxy-route (:add-proxy-route webserver-service)] (add-proxy-route target path opts))) OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webserver/000077500000000000000000000000001527232126200333225ustar00rootroot00000000000000jetty_config.clj000066400000000000000000000516041527232126200364270ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-config (:require [clojure.string :as str] [clojure.tools.logging :as log] [me.raynes.fs :as fs] [puppetlabs.i18n.core :as i18n] [puppetlabs.kitchensink.core :refer [parse-bool uuid]] [puppetlabs.kitchensink.file :refer [nofollow-links]] [puppetlabs.ssl-utils.core :as ssl] [schema.core :as schema]) (:import (ch.qos.logback.access.jetty RequestLogImpl) (ch.qos.logback.core CoreConstants) (com.puppetlabs.ssl_utils SSLUtils) (com.puppetlabs.trapperkeeper.services.webserver.jetty.utils MDCAccessLogConverter ModifiedRequestLogImpl) (java.io File FileInputStream) (java.nio.file Files) (java.security KeyStore) (java.util HashMap) (org.eclipse.jetty.server Server))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Constants / Defaults ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; ;;; NOTE: We are making a decisive move away from overriding Jetty's ;;; implicit default values for settings when downstream TK apps do not ;;; explicitly provide values for them. Please see the comments/tests in ;;; `jetty_default_config_test.clj` for full details. ;;; ;;; Below we are making a handful of deliberate exceptions to this rule, ;;; but please do not perpetuate this pattern without a compelling reason to ;;; do so. ;;; ;;; Host/port settings ;;; ;;; These are really common and fairly benign, and removing them would probably ;;; only serve to make the bare configuration more onerous. ;;; (def default-http-port 8080) (def default-https-port 8081) (def default-host "localhost") ;;; ;;; Security-related settings ;;; ;;; After some discussion, we decided that it was probably still appropriate to ;;; override Jetty's defaults for these security-related settings. In the event ;;; that a vulnerability like "POODLE" is announced (where we needed to remove ;;; the SSLv3 protocol from the list of allowed protocols), we would need to do ;;; a release of tk-j12 to address it no matter what. The choices would then be ;;; to update our own defaults for security-related settings, or, if we're not ;;; imposing our own defaults, to try to upgrade to a new version of Jetty where ;;; their implicit defaults reflect the security issue. The latter is far more ;;; risky for our downstream apps, thus it was decided that it makes sense to ;;; keep these overrides. (def tls-1-dot-3-ciphers ["TLS_AES_128_GCM_SHA256" "TLS_AES_256_GCM_SHA384"]) (def tls-1-dot-2-ciphers ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384" "TLS_DHE_RSA_WITH_AES_128_GCM_SHA256"]) (def acceptable-ciphers (into [] (concat tls-1-dot-3-ciphers tls-1-dot-2-ciphers))) (def fips-tls-1-dot-2-ciphers ["TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"]) (def acceptable-ciphers-fips (into [] (concat tls-1-dot-3-ciphers fips-tls-1-dot-2-ciphers))) (def default-protocols ["TLSv1.3" "TLSv1.2"]) (def default-client-auth :need) (def default-allow-renegotiation false) (def default-sni-required false) ;;; ;;; JMX ;;; ;;; The JMX metrics seem valuable enough, and inexpensive enough, to warrant ;;; leaving them on by default. (def default-jmx-enable "true") ;;; ;;; Timeouts ;;; ;;; The stop timeout is the graceful shutdown period beteween when a server is asked to stop and when ;; any open connections are closed. This default came from Jetty 9.4, which changed to 0 in Jetty 10 (def default-shutdown-timeout-seconds 30) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Schemas (def StaticContent {:resource schema/Str :path schema/Str (schema/optional-key :follow-links) schema/Bool}) (def WebserverRawConfig {(schema/optional-key :port) schema/Int (schema/optional-key :host) schema/Str (schema/optional-key :acceptor-threads) schema/Int (schema/optional-key :selector-threads) schema/Int (schema/optional-key :max-threads) schema/Int (schema/optional-key :queue-max-size) schema/Int (schema/optional-key :request-header-max-size) schema/Int (schema/optional-key :request-body-max-size) schema/Int (schema/optional-key :so-linger-seconds) schema/Int (schema/optional-key :idle-timeout-milliseconds) schema/Int (schema/optional-key :ssl-port) schema/Int (schema/optional-key :ssl-host) schema/Str (schema/optional-key :ssl-key) schema/Str (schema/optional-key :ssl-cert) schema/Str (schema/optional-key :ssl-cert-chain) schema/Str (schema/optional-key :ssl-ca-cert) schema/Str (schema/optional-key :ssl-acceptor-threads) schema/Int (schema/optional-key :ssl-selector-threads) schema/Int (schema/optional-key :keystore) schema/Str (schema/optional-key :truststore) schema/Str (schema/optional-key :key-password) schema/Str (schema/optional-key :trust-password) schema/Str (schema/optional-key :cipher-suites) (schema/either schema/Str [schema/Str]) (schema/optional-key :ssl-protocols) (schema/either schema/Str [schema/Str]) (schema/optional-key :client-auth) schema/Str (schema/optional-key :ssl-crl-path) schema/Str (schema/optional-key :jmx-enable) schema/Str (schema/optional-key :default-server) schema/Bool (schema/optional-key :static-content) [StaticContent] (schema/optional-key :gzip-enable) schema/Bool (schema/optional-key :access-log-config) schema/Str (schema/optional-key :shutdown-timeout-seconds) schema/Int (schema/optional-key :allow-renegotiation) schema/Bool (schema/optional-key :sni-required) schema/Bool}) (def MultiWebserverRawConfigUnvalidated {schema/Keyword WebserverRawConfig}) (defn one-default? [config] (->> config vals (filter :default-server) count (>= 1))) (defn map-of-maps? [x] (and (map? x) (every? map? (vals x)))) (def MultiWebserverRawConfig (schema/both MultiWebserverRawConfigUnvalidated (schema/pred one-default? 'one-default?))) (def WebserverServiceRawConfig (schema/conditional map-of-maps? MultiWebserverRawConfig :else WebserverRawConfig)) (def WebserverSslPemConfig {:ssl-key schema/Str :ssl-cert schema/Str (schema/optional-key :ssl-cert-chain) schema/Str :ssl-ca-cert schema/Str}) (def WebserverSslKeystoreConfig {:keystore KeyStore :key-password schema/Str :truststore KeyStore (schema/optional-key :trust-password) schema/Str}) (def WebserverSslClientAuth (schema/enum :need :want :none)) (def WebserverConnectorCommon {:request-header-max-size (schema/maybe schema/Int) :idle-timeout-milliseconds (schema/maybe schema/Int)}) (def WebserverConnector (merge WebserverConnectorCommon {:host schema/Str :port schema/Int :acceptor-threads (schema/maybe schema/Int) :selector-threads (schema/maybe schema/Int)})) (def WebserverSslContextFactory {:keystore-config WebserverSslKeystoreConfig :client-auth WebserverSslClientAuth (schema/optional-key :ssl-crl-path) (schema/maybe schema/Str) :cipher-suites [schema/Str] :protocols (schema/maybe [schema/Str]) (schema/optional-key :allow-renegotiation) (schema/maybe schema/Bool) (schema/optional-key :sni-required) (schema/maybe schema/Bool)}) (def WebserverClientSslContextFactory (dissoc WebserverSslContextFactory :client-auth)) (def WebserverSslConnector (merge WebserverConnector WebserverSslContextFactory)) (def HasConnector (schema/either (schema/pred #(contains? % :http) 'has-http-connector?) (schema/pred #(contains? % :https) 'has-https-connector?))) (def WebserverConfig (schema/both HasConnector {(schema/optional-key :http) WebserverConnector (schema/optional-key :https) WebserverSslConnector :max-threads (schema/maybe schema/Int) :queue-max-size (schema/maybe schema/Int) :jmx-enable schema/Bool})) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Conversion functions (raw config -> schema) (schema/defn ^:always-validate reject-post-config-script! [config :- (schema/maybe WebserverRawConfig)] (when (and config (contains? config :post-config-script)) (throw (IllegalArgumentException. (i18n/trs "The ''post-config-script'' setting has been removed. Please remove it from your config."))))) (schema/defn ^:always-validate warn-if-so-linger-set [config :- (schema/maybe WebserverRawConfig)] (when (and config (:so-linger-seconds config)) (log/warn (i18n/trs "The so-linger-seconds setting was found to cause undefined behavior and was removed. The current value will be ignored.")))) (schema/defn ^:always-validate maybe-get-pem-config! :- (schema/maybe WebserverSslPemConfig) [config :- WebserverRawConfig] (let [pem-required-keys [:ssl-key :ssl-cert :ssl-ca-cert] pem-config (select-keys config pem-required-keys)] (condp = (count pem-config) 3 (if-let [ssl-cert-chain (:ssl-cert-chain config)] (assoc pem-config :ssl-cert-chain ssl-cert-chain) pem-config) 0 nil (throw (IllegalArgumentException. (i18n/trs "Found SSL config options: {0}; If configuring SSL from PEM files, you must provide all of the following options: {1}" (keys pem-config) pem-required-keys)))))) (schema/defn ^:always-validate get-x509s-from-ssl-cert-pem :- (schema/pred ssl/certificate-list?) [ssl-cert :- schema/Str ssl-cert-chain :- (schema/maybe schema/Str)] (if-not (fs/readable? ssl-cert) (throw (IllegalArgumentException. (i18n/trs "Unable to open ''ssl-cert'' file: {0}" ssl-cert)))) (let [certs (ssl/pem->certs ssl-cert)] (if (= 0 (count certs)) (throw (Exception. (i18n/trs "No certs found in ''ssl-cert'' file: {0}" ssl-cert)))) (if ssl-cert-chain [(first certs)] certs))) (schema/defn ^:always-validate get-x509s-from-ssl-cert-chain-pem :- (schema/pred ssl/certificate-list?) [ssl-cert-chain :- (schema/maybe schema/Str)] (if ssl-cert-chain (do (if-not (fs/readable? ssl-cert-chain) (throw (IllegalArgumentException. (i18n/trs "Unable to open ''ssl-cert-chain'' file: {0}" ssl-cert-chain)))) (ssl/pem->certs ssl-cert-chain)) [])) (schema/defn ^:always-validate construct-ssl-x509-cert-chain :- (schema/pred ssl/certificate-list?) [ssl-cert :- schema/Str ssl-cert-chain :- (schema/maybe schema/Str)] (let [ssl-cert-x509s (get-x509s-from-ssl-cert-pem ssl-cert ssl-cert-chain) ssl-cert-chain-x509s (get-x509s-from-ssl-cert-chain-pem ssl-cert-chain)] (into [] (concat ssl-cert-x509s ssl-cert-chain-x509s)))) (schema/defn ^:always-validate pem-ssl-config->keystore-ssl-config :- WebserverSslKeystoreConfig [{:keys [ssl-ca-cert ssl-key ssl-cert ssl-cert-chain]} :- WebserverSslPemConfig] (let [key-password (uuid) ssl-x509-chain (construct-ssl-x509-cert-chain ssl-cert ssl-cert-chain)] {:truststore (-> (ssl/keystore) (ssl/assoc-certs-from-file! "CA Certificate" ssl-ca-cert)) :key-password key-password :keystore (-> (ssl/keystore) (ssl/assoc-private-key! "Private Key" (ssl/pem->private-key ssl-key) key-password ssl-x509-chain))})) (schema/defn ^:always-validate warn-if-keystore-ssl-configs-found! [config :- WebserverRawConfig] (let [keystore-ssl-config-keys [:keystore :truststore :key-password :trust-password] keystore-ssl-config (select-keys config keystore-ssl-config-keys)] (when (pos? (count keystore-ssl-config)) (log/warn (i18n/trs "Found settings for both keystore-based and PEM-based SSL; using PEM-based settings, ignoring {0}" (keys keystore-ssl-config)))))) (schema/defn ^:always-validate get-jks-keystore-config! :- WebserverSslKeystoreConfig [{:keys [truststore keystore key-password trust-password]} :- WebserverRawConfig] (when (some nil? [truststore keystore key-password trust-password]) (throw (IllegalArgumentException. ^String (i18n/trs "Missing some SSL configuration; must provide either :ssl-cert, :ssl-key, and :ssl-ca-cert, OR :truststore, :trust-password, :keystore, and :key-password.")))) {:keystore (doto (ssl/keystore) (.load (FileInputStream. ^String keystore) (.toCharArray key-password))) :truststore (doto (ssl/keystore) (.load (FileInputStream. ^String truststore) (.toCharArray trust-password))) :key-password key-password :trust-password trust-password}) (schema/defn ^:always-validate get-keystore-config! :- WebserverSslKeystoreConfig [config :- WebserverRawConfig] (if-let [pem-config (maybe-get-pem-config! config)] (do (warn-if-keystore-ssl-configs-found! config) (pem-ssl-config->keystore-ssl-config pem-config)) (get-jks-keystore-config! config))) (schema/defn ^:always-validate get-client-auth! :- WebserverSslClientAuth [config :- WebserverRawConfig] (let [client-auth (:client-auth config)] (cond (nil? client-auth) default-client-auth (contains? #{"need" "want" "none"} client-auth) (keyword client-auth) :else (throw (IllegalArgumentException. (i18n/trs "Unexpected value found for client auth config option: {0}. Expected need, want, or none." client-auth)))))) (schema/defn ^:always-validate get-ssl-crl-path! :- (schema/maybe schema/Str) [config :- WebserverRawConfig] (if-let [ssl-crl-path (:ssl-crl-path config)] (if (fs/readable? ssl-crl-path) ssl-crl-path (throw (IllegalArgumentException. (i18n/trs "Non-readable path specified for ssl-crl-path option: {0}" ssl-crl-path)))))) (schema/defn get-or-parse-sequential-config-value :- [schema/Str] "Some config values can be entered as either a vector of strings or a single comma-separated string. Get the value for the given config key, parsing it into a seq if it's a string, or returning a default if it's not provided." [config :- WebserverRawConfig key :- schema/Keyword default :- [schema/Str]] (let [value (key config)] (cond (string? value) (map str/trim (str/split value #",")) value value :else default))) (defn get-cipher-suites-config [config] (get-or-parse-sequential-config-value config :cipher-suites (if (SSLUtils/isFIPS) acceptable-ciphers-fips acceptable-ciphers))) (defn get-ssl-protocols-config [config] (get-or-parse-sequential-config-value config :ssl-protocols default-protocols)) (schema/defn ^:always-validate contains-keys? :- schema/Bool [config :- WebserverRawConfig keys :- #{schema/Keyword}] (boolean (some #(contains? config %) keys))) (defn contains-http-connector? [config] (contains-keys? config #{:port :host})) (schema/defn ^:always-validate common-connector-config :- WebserverConnectorCommon [config :- WebserverRawConfig] {:request-header-max-size (:request-header-max-size config) :idle-timeout-milliseconds (:idle-timeout-milliseconds config)}) (schema/defn ^:always-validate maybe-get-http-connector :- (schema/maybe WebserverConnector) [config :- WebserverRawConfig] (if (contains-http-connector? config) (merge (common-connector-config config) {:host (or (:host config) default-host) :port (or (:port config) default-http-port) :acceptor-threads (:acceptor-threads config) :selector-threads (:selector-threads config)}))) (schema/defn ^:always-validate contains-https-connector? :- schema/Bool [config :- WebserverRawConfig] (contains-keys? config #{:ssl-port :ssl-host})) (schema/defn ^:always-validate maybe-get-https-connector :- (schema/maybe WebserverSslConnector) [config :- WebserverRawConfig] (if (contains-https-connector? config) (merge (common-connector-config config) {:host (or (:ssl-host config) default-host) :port (or (:ssl-port config) default-https-port) :acceptor-threads (:ssl-acceptor-threads config) :selector-threads (:ssl-selector-threads config) :keystore-config (get-keystore-config! config) :cipher-suites (get-cipher-suites-config config) :protocols (get-ssl-protocols-config config) :client-auth (get-client-auth! config) :ssl-crl-path (get-ssl-crl-path! config) :allow-renegotiation (get config :allow-renegotiation default-allow-renegotiation) :sni-required (or (:sni-required config) default-sni-required)}))) (schema/defn ^:always-validate maybe-add-http-connector :- {(schema/optional-key :http) WebserverConnector schema/Keyword schema/Any} [acc config :- WebserverRawConfig] (if-let [http-connector (maybe-get-http-connector config)] (assoc acc :http http-connector) acc)) (schema/defn ^:always-validate maybe-add-https-connector :- {(schema/optional-key :https) WebserverSslConnector schema/Keyword schema/Any} [acc config :- WebserverRawConfig] (if-let [https-connector (maybe-get-https-connector config)] (assoc acc :https https-connector) acc)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Private helper functions (defn validate-config [config] (when-not (one-default? config) (throw (IllegalArgumentException. (i18n/trs "Error: More than one default server specified in configuration"))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Public (schema/defn ^:always-validate process-config :- WebserverConfig [config :- WebserverRawConfig] (reject-post-config-script! config) (warn-if-so-linger-set config) (let [result (-> {} (maybe-add-http-connector config) (maybe-add-https-connector config) (assoc :max-threads (:max-threads config)) (assoc :queue-max-size (:queue-max-size config)) (assoc :jmx-enable (parse-bool (get config :jmx-enable default-jmx-enable))))] (when-not (some #(contains? result %) [:http :https]) (throw (IllegalArgumentException. ^String (i18n/trs "Either host, port, ssl-host, or ssl-port must be specified on the config in order for the server to be started")))) result)) (schema/defn ^:always-validate init-log-handler :- (schema/maybe RequestLogImpl) [config :- WebserverRawConfig] (let [filename (:access-log-config config) path (.toPath (File. ^String filename))] (if (Files/isRegularFile path nofollow-links) (do (log/debug (i18n/trs "Found access-log file at {0}" filename)) (let [pattern-rules (HashMap.) logger (ModifiedRequestLogImpl.)] (doseq [pattern ["X" "mdc"]] (.put pattern-rules pattern (.getName MDCAccessLogConverter))) (.putObject logger CoreConstants/PATTERN_RULE_REGISTRY pattern-rules) (log/info (i18n/trs "Enabling access logger using file {0}" filename)) (.setFileName logger filename) (.setQuiet logger false) logger)) (log/info (i18n/trs "Access logging file not found at {0}" filename))))) (defn maybe-init-log-handler [config] (if (:access-log-config config) (init-log-handler config) (log/info (i18n/trs "Access log configuration not specified")))) jetty_core.clj000066400000000000000000001573061527232126200361200ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-core (:require [clojure.string :as str] [clojure.tools.logging :as log] [me.raynes.fs :as fs] [puppetlabs.i18n.core :as i18n] [puppetlabs.trapperkeeper.services.protocols.filesystem-watch-service :as watch-protocol] [puppetlabs.trapperkeeper.services.webserver.jetty-config :as config] [puppetlabs.trapperkeeper.services.webserver.normalized-uri-helpers :as normalized-uri-helpers] [ring.util.codec :as codec] [ring.util.jakarta.servlet :as servlet] [schema.core :as schema]) (:import (clojure.lang Atom) (com.puppetlabs.ssl_utils SSLUtils) (com.puppetlabs.trapperkeeper.services.webserver.jetty.utils InternalSslContextFactory MDCHandler) (java.lang.management ManagementFactory) (java.net URI) (java.security Security) (java.util.concurrent TimeoutException ExecutionException) (jakarta.servlet Servlet ServletContextListener) (jakarta.servlet.http HttpServletResponse) (org.eclipse.jetty.client HttpClient RedirectProtocolHandler) (org.eclipse.jetty.client.transport HttpClientTransportDynamic HttpClientConnectionFactory) (org.eclipse.jetty.http HttpMethod MimeTypes UriCompliance) (org.eclipse.jetty.io ClientConnectionFactory$Info ClientConnector) (org.eclipse.jetty.jmx MBeanContainer) (org.eclipse.jetty.ee10.proxy ProxyServlet) (org.eclipse.jetty.server AbstractConnectionFactory ConnectionFactory CustomRequestLog Handler Handler$Wrapper Handler$Sequence HttpConfiguration HttpConnectionFactory Request Response SecureRequestCustomizer Server ServerConnector Slf4jRequestLogWriter) (org.eclipse.jetty.server.handler ContextHandler ContextHandlerCollection GracefulHandler) (org.eclipse.jetty.server.handler.gzip GzipHandler) (org.eclipse.jetty.ee10.servlet DefaultServlet ServletContextHandler ServletHolder) (org.eclipse.jetty.util BlockingArrayQueue Callback URIUtil) (org.eclipse.jetty.util.resource ResourceFactory) (org.eclipse.jetty.util.ssl SslContextFactory$Client SslContextFactory$Server) (org.eclipse.jetty.util.thread QueuedThreadPool) (org.eclipse.jetty.ee10.webapp WebAppContext))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; JDK SecurityProvider Hack ;; Work around an issue with OpenJDK's PKCS11 implementation preventing TLSv1 ;; connections from working correctly ;; ;; http://stackoverflow.com/questions/9586162/openjdk-and-php-ssl-connection-fails ;; https://bugs.launchpad.net/ubuntu/+source/openjdk-6/+bug/948875 (if (re-find #"OpenJDK" (System/getProperty "java.vm.name")) (try (let [klass (Class/forName "sun.security.pkcs11.SunPKCS11") blacklist (filter #(instance? klass %) (Security/getProviders))] (doseq [provider blacklist] (log/info (i18n/trs "Removing buggy security provider {0}" provider)) (Security/removeProvider (.getName provider)))) (catch ClassNotFoundException e) (catch Throwable e (log/error e (i18n/trs "Could not remove security providers; HTTPS may not work!"))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Bouncy Castle logs via java.util.logging, and is noisy during our ;;; requests. Redirect this logging into SL4J, which lets us control ;;; it via logback. (if-let [logging-resource (clojure.java.io/resource "logging-router.properties")] (-> (java.util.logging.LogManager/getLogManager) (.readConfiguration (.openStream logging-resource))) (log/error (i18n/trs "logging-router.properties not found, extra logging will occur"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Schemas (def ProxyTarget {:host schema/Str :path schema/Str :port schema/Int}) (def CommonOptions {(schema/optional-key :server-id) schema/Keyword (schema/optional-key :redirect-if-no-trailing-slash) schema/Bool (schema/optional-key :normalize-request-uri) schema/Bool}) (def ContextHandlerOptions (assoc CommonOptions (schema/optional-key :context-listeners) [ServletContextListener] (schema/optional-key :follow-links) schema/Bool)) (def ServletHandlerOptions (assoc CommonOptions (schema/optional-key :servlet-init-params) {schema/Str schema/Str})) (def ProxySslConfig (merge config/WebserverSslPemConfig {(schema/optional-key :cipher-suites) [schema/Str] (schema/optional-key :protocols) (schema/maybe [schema/Str]) (schema/optional-key :allow-renegotiation) (schema/maybe [schema/Bool])})) (defn positive-integer? [i] (and (integer? i) (pos? i))) (def PosInt "Any integer z in Z where z > 0." (schema/pred positive-integer? 'positive-integer?)) (def ProxyOptions (assoc CommonOptions (schema/optional-key :scheme) (schema/enum :orig :http :https "orig" "http" "https") (schema/optional-key :ssl-config) (schema/conditional keyword? (schema/eq :use-server-config) map? ProxySslConfig) (schema/optional-key :rewrite-uri-callback-fn) (schema/pred ifn?) (schema/optional-key :callback-fn) (schema/pred ifn?) (schema/optional-key :request-buffer-size) schema/Int (schema/optional-key :follow-redirects) schema/Bool (schema/optional-key :idle-timeout) PosInt)) (def ContextEndpoint {:type (schema/eq :context) :base-path schema/Str (schema/optional-key :context-listeners) (schema/maybe [ServletContextListener])}) (def RingEndpoint {:type (schema/eq :ring)}) (def ServletEndpoint {:type (schema/eq :servlet) :servlet java.lang.Class}) (def WarEndpoint {:type (schema/eq :war) :war-path schema/Str}) (def ProxyEndpoint {:type (schema/eq :proxy) :target-host schema/Str :target-port schema/Int :target-path schema/Str}) (def Endpoint (schema/conditional #(-> % :type (= :context)) ContextEndpoint #(-> % :type (= :ring)) RingEndpoint #(-> % :type (= :servlet)) ServletEndpoint #(-> % :type (= :war)) WarEndpoint #(-> % :type (= :proxy)) ProxyEndpoint)) (def RegisteredEndpoints {schema/Str [Endpoint]}) (def ServerContextState {:mbean-container (schema/maybe MBeanContainer) :overrides-read-by-webserver schema/Bool :overrides (schema/maybe {schema/Keyword schema/Any}) :endpoints RegisteredEndpoints :ssl-context-server-factory (schema/maybe SslContextFactory$Server) :ssl-context-client-factory (schema/maybe SslContextFactory$Client)}) (def ServerContext {:state (schema/atom ServerContextState) :handlers ContextHandlerCollection :server (schema/maybe Server)}) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Utility Functions (defn- remove-leading-slash [s] (str/replace s #"^\/" "")) (defn- with-leading-slash [s] (if (.startsWith s "/") s (str "/" s))) (schema/defn ^:always-validate started? :- Boolean "A predicate that indicates whether or not the webserver-context contains a Jetty Server object." [webserver-context :- ServerContext] (instance? Server (:server webserver-context))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; SSL Context Functions (schema/defn ^:always-validate ssl-context-client-factory :- SslContextFactory$Client "Creates a new SslContextFactory instance from a map of SSL config options." [{:keys [keystore-config ssl-crl-path cipher-suites protocols allow-renegotiation]} :- config/WebserverClientSslContextFactory] (let [context (doto (SslContextFactory$Client.) (.setKeyStore (:keystore keystore-config)) (.setKeyStorePassword (:key-password keystore-config)) (.setTrustStore (:truststore keystore-config)) ;; Need to clear out the default cipher suite exclude list so ;; that Jetty doesn't potentially remove one or more ciphers ;; that we want to be included. (.setExcludeCipherSuites (into-array String [])) (.setIncludeCipherSuites (into-array String cipher-suites)) ;; Need to clear out the default protocols exclude list so ;; that Jetty doesn't potentially remove one or more protocols ;; that we want to be included. (.setExcludeProtocols (into-array String [])) (.setIncludeProtocols (into-array String (filter #(not= "sslv3" (str/lower-case %)) protocols))))] (when (empty? (.getIncludeProtocols context)) (.setIncludeProtocols context (into-array String [SSLUtils/TLS_PROTOCOL]))) (when (SSLUtils/isFIPS) (doto context (.setKeyStoreType SSLUtils/BOUNCYCASTLE_FIPS_KEYSTORE) (.setTrustStoreType SSLUtils/BOUNCYCASTLE_FIPS_KEYSTORE) (.setKeyStoreProvider SSLUtils/FIPS_PROVIDER_CLASS) (.setTrustStoreProvider SSLUtils/FIPS_PROVIDER_CLASS) (.setKeyManagerFactoryAlgorithm SSLUtils/PKIX_KEYMANAGER_ALGO) (.setTrustManagerFactoryAlgorithm SSLUtils/PKIX_KEYMANAGER_ALGO))) (if (:trust-password keystore-config) (.setTrustStorePassword context (:trust-password keystore-config))) (if allow-renegotiation (.setRenegotiationAllowed context true) (.setRenegotiationAllowed context false)) (when ssl-crl-path (.setCrlPath context ssl-crl-path) ; .setValidatePeerCerts needs to be called with a value of 'true' in ; order to force Jetty to actually use the CRL when validating client ; certificates for a connection. (.setValidatePeerCerts context true)) context)) (schema/defn ^:always-validate ssl-context-server-factory :- SslContextFactory$Server "Creates a new SslContextFactory instance from a map of SSL config options." [{:keys [keystore-config client-auth ssl-crl-path cipher-suites protocols allow-renegotiation sni-required]} :- config/WebserverSslContextFactory] (when (some #(= "sslv3" %) (map str/lower-case protocols)) (log/warn (i18n/trs "`ssl-protocols` contains SSLv3, a protocol with known vulnerabilities; ignoring"))) (let [context (doto (InternalSslContextFactory.) (.setKeyStore (:keystore keystore-config)) (.setKeyStorePassword (:key-password keystore-config)) (.setTrustStore (:truststore keystore-config)) ;; Need to clear out the default cipher suite exclude list so ;; that Jetty doesn't potentially remove one or more ciphers ;; that we want to be included. (.setExcludeCipherSuites (into-array String [])) (.setIncludeCipherSuites (into-array String cipher-suites)) ;; Need to clear out the default protocols exclude list so ;; that Jetty doesn't potentially remove one or more protocols ;; that we want to be included. (.setExcludeProtocols (into-array String [])) (.setIncludeProtocols (into-array String (filter #(not= "sslv3" (str/lower-case %)) protocols))))] (when (empty? (.getIncludeProtocols context)) (log/warn (i18n/trs "When `ssl-protocols` is empty, a default of {0} is assumed" SSLUtils/TLS_PROTOCOL)) (.setIncludeProtocols context (into-array String [SSLUtils/TLS_PROTOCOL]))) (when (SSLUtils/isFIPS) (doto context (.setKeyStoreType SSLUtils/BOUNCYCASTLE_FIPS_KEYSTORE) (.setTrustStoreType SSLUtils/BOUNCYCASTLE_FIPS_KEYSTORE) (.setKeyStoreProvider SSLUtils/FIPS_PROVIDER_CLASS) (.setTrustStoreProvider SSLUtils/FIPS_PROVIDER_CLASS) (.setKeyManagerFactoryAlgorithm SSLUtils/PKIX_KEYMANAGER_ALGO) (.setTrustManagerFactoryAlgorithm SSLUtils/PKIX_KEYMANAGER_ALGO))) (if (:trust-password keystore-config) (.setTrustStorePassword context (:trust-password keystore-config))) (case client-auth :need (.setNeedClientAuth context true) :want (.setWantClientAuth context true) nil) (if allow-renegotiation (.setRenegotiationAllowed context true) (.setRenegotiationAllowed context false)) (if sni-required (.setSniRequired context true) (.setSniRequired context false)) (when ssl-crl-path (.setCrlPath context ssl-crl-path) ; .setValidatePeerCerts needs to be called with a value of 'true' in ; order to force Jetty to actually use the CRL when validating client ; certificates for a connection. (.setValidatePeerCerts context true)) context)) (schema/defn ^:always-validate get-proxy-client-context-factory :- SslContextFactory$Client [ssl-config :- ProxySslConfig] (ssl-context-client-factory {:keystore-config (config/pem-ssl-config->keystore-ssl-config ssl-config) :cipher-suites (or (:cipher-suites ssl-config) (if (SSLUtils/isFIPS) config/acceptable-ciphers-fips config/acceptable-ciphers)) :protocols (or (:protocols ssl-config) config/default-protocols) :allow-renegotiation (or (:allow-renegotiation ssl-config) config/default-allow-renegotiation)})) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Jetty Server / Connector Functions (defn- http-configuration [request-header-size] (let [customizer (SecureRequestCustomizer. false) _ (.setSniRequired customizer false) http-config (doto (HttpConfiguration.) (.addCustomizer customizer) (.setSendDateHeader true) (.setSendServerVersion false) ;; LEGACY uri compliance mode that models Jetty-9.4 behavior by allowing ;; UriCompliance.Violation.AMBIGUOUS_PATH_SEGMENT, UriCompliance.Violation.AMBIGUOUS_EMPTY_SEGMENT, ;; UriCompliance.Violation.AMBIGUOUS_PATH_SEPARATOR, UriCompliance.Violation.AMBIGUOUS_PATH_ENCODING ;; and UriCompliance.Violation.UTF16_ENCODINGS ;; https://www.eclipse.org/jetty/javadoc/jetty-12/org/eclipse/jetty/http/UriCompliance.html#LEGACY (.setUriCompliance UriCompliance/LEGACY))] (when request-header-size (.setRequestHeaderSize http-config request-header-size)) http-config)) (defn- connection-factories [request-header-size ^SslContextFactory$Server ssl-ctxt-factory] (let [http-config (http-configuration request-header-size) factories (into-array ConnectionFactory [(HttpConnectionFactory. http-config)])] (if ssl-ctxt-factory (AbstractConnectionFactory/getFactories ssl-ctxt-factory factories) factories))) (defn- thread-count [setting] (if setting setting -1)) (schema/defn ^:always-validate connector* :- ServerConnector [server :- Server config :- (merge config/WebserverConnector {schema/Keyword schema/Any}) ssl-ctxt-factory :- (schema/maybe SslContextFactory$Server)] (let [request-size (:request-header-max-size config) connector (doto (ServerConnector. server nil nil nil (thread-count (:acceptor-threads config)) (thread-count (:selector-threads config)) (connection-factories request-size ssl-ctxt-factory)) (.setPort (:port config)) (.setHost (:host config)))] (when-let [idle-timeout (:idle-timeout-milliseconds config)] (.setIdleTimeout connector idle-timeout)) connector)) (schema/defn ^:always-validate ssl-connector :- ServerConnector "Creates a ssl ServerConnector instance." [server :- Server ssl-ctxt-factory :- SslContextFactory$Server config :- config/WebserverSslConnector] (connector* server config ssl-ctxt-factory)) (schema/defn ^:always-validate plaintext-connector :- ServerConnector [server :- Server config :- config/WebserverConnector] (connector* server config nil)) (schema/defn ^:always-validate queue-thread-pool :- (schema/maybe QueuedThreadPool) [max-threads :- (schema/maybe schema/Int) queue-max-size :- (schema/maybe schema/Int)] (if (or max-threads queue-max-size) (let [thread-pool (if max-threads (QueuedThreadPool. max-threads) (QueuedThreadPool.))] (if queue-max-size ;; The code below is definitely not ideal, but there isn't a way to set ;; the maximum capacity of the QueuedThreadPool's BlockingArrayQueue ;; after construction. We're trying to avoid hard-coding our own ;; defaults for other settings that we want Jetty to control, e.g., the ;; initial capacity of the queue and minimum number of threads. By ;; reconstructing the QueuedThreadPool here, we can use Jetty's defaults ;; for settings unrelated to `queue-max-size`. ;; ;; QueuedThreadPool and BlockingArrayQueue construction isn't too ;; expensive. It mostly involves some initial memory allocations. The ;; more expensive work - where threads are actually started and the ;; queue expands to fulfill new requests - would only happen after the ;; QueuedThreadPool were started. That won't happen for the ;; `thread-pool` instance from above, which just gets thrown away as ;; this function falls out of scope without ever having been started. ;; Also, this function would likely only be called once per server ;; startup where a `queue-max-size` were configured. ;; ;; The QueuedThreadPool constructor sets the `queue-capacity` and ;; `queue-grow-by` based on the minimum number of threads available ;; in the pool. See https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java#L101-L105. ;; That algorithm is essentially duplicated here, with the only ;; difference being that if `queue-max-size` is smaller than the ;; minimum number of threads, the `queue-capacity` and `queue-grow-by` ;; are reduced to the `queue-max-size` in order to avoid the ;; BlockingArrayQueue constructor throwing an IllegalArgumentException. (let [min-threads (.getMinThreads thread-pool) queue-capacity (min queue-max-size min-threads) queue-grow-by (min queue-max-size min-threads)] (QueuedThreadPool. (.getMaxThreads thread-pool) min-threads (.getIdleTimeout thread-pool) (BlockingArrayQueue. queue-capacity queue-grow-by queue-max-size))) thread-pool)))) (schema/defn ^:always-validate create-server :- Server "Construct a Jetty Server instance." [webserver-context :- ServerContext config :- config/WebserverConfig] (let [server (if-let [^QueuedThreadPool pool (queue-thread-pool (:max-threads config) (:queue-max-size config))] (Server. pool) (Server.))] (when (:jmx-enable config) (let [mb-container (MBeanContainer. (ManagementFactory/getPlatformMBeanServer))] (doto server (.addEventListener mb-container) (.addBean mb-container)) (swap! (:state webserver-context) assoc :mbean-container mb-container))) (when (:http config) (let [connector (plaintext-connector server (:http config))] (.addConnector server connector))) (when-let [https (:https config)] (let [ssl-ctxt-server-factory (ssl-context-server-factory (select-keys https [:keystore-config :client-auth :ssl-crl-path :cipher-suites :allow-renegotiation :protocols :sni-required])) ssl-ctx-client-factory (ssl-context-client-factory (select-keys https [:keystore-config :ssl-crl-path :cipher-suites :allow-renegotiation :protocols])) connector (ssl-connector server ssl-ctxt-server-factory https)] (.addConnector server connector) (swap! (:state webserver-context) assoc :ssl-context-server-factory ssl-ctxt-server-factory :ssl-context-client-factory ssl-ctx-client-factory))) server)) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; GZip Functions ;; TODO: make all of this gzip-mime-type stuff configurable (defn- gzip-excluded-mime-types "Build up a list of mime types that should not be candidates for gzip compression in responses." [] ;; In Jetty 12, MimeTypes API changed. We use getMimeMap() from DEFAULTS ;; to get known mime types and filter for binary content types. (let [binary-types (filter #(or (.startsWith ^String % "image/") (.startsWith ^String % "audio/") (.startsWith ^String % "video/")) (keys (.getMimeMap (MimeTypes/DEFAULTS)))) all-types (concat binary-types ["application/compress" "application/zip" "application/gzip" "text/event-stream"])] (into-array String all-types))) (defn- gzip-handler "Given a handler, wrap it with a GzipHandler that will compress the response when appropriate." [handler] (doto (GzipHandler.) (.setHandler handler) (.setExcludedMimeTypes (gzip-excluded-mime-types)) (.addIncludedMethods (into-array [(.asString HttpMethod/POST)])))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Handler Helper Functions (schema/defn ^:always-validate add-handler :- ContextHandler [webserver-context :- ServerContext ^ContextHandler handler :- ContextHandler enable-trailing-slash-redirect? :- schema/Bool] (.setAllowNullPathInContext handler (not enable-trailing-slash-redirect?)) (.addHandler (:handlers webserver-context) handler) ;; If this handler is being added after the server has been started, we ;; need to mark the handler as "managed" so that the server will stop the ;; handler when the server is stopped. We also need to manually start the ;; handler. The server takes care of marking handlers as managed and starting ;; them if the handlers are already registered when the server is started. (if-let [server (.getServer handler)] (when (and (.isRunning server) (not (.isRunning handler))) (.manage (:handlers webserver-context) handler) (.start handler))) handler) (schema/defn ^:always-validate proxy-servlet :- ProxyServlet "Create an instance of Jetty's `ProxyServlet` that will proxy requests at a given context to another host." [webserver-context :- ServerContext target :- ProxyTarget options :- ProxyOptions] (let [custom-ssl-ctxt-factory (if (map? (:ssl-config options)) ^SslContextFactory$Client (get-proxy-client-context-factory (:ssl-config options)) (log/info (i18n/trs "Proxy not configured with custom ssl, using server default"))) {:keys [request-buffer-size idle-timeout]} options] (proxy [ProxyServlet] [] (rewriteTarget [req] (let [query (.getQueryString req) scheme (let [target-scheme (:scheme options)] (condp = target-scheme nil (.getScheme req) :orig (.getScheme req) "orig" (.getScheme req) :http "http" :https "https" "http" target-scheme "https" target-scheme)) context-path (.getPathInfo req)] (let [target-uri (URI. scheme nil (:host target) (:port target) (with-leading-slash (URIUtil/addPaths (:path target) context-path)) (codec/url-decode (str query)) nil)] (if-let [rewrite-uri-callback-fn (:rewrite-uri-callback-fn options)] (str (rewrite-uri-callback-fn target-uri req)) (str target-uri))))) (newHttpClient [] (let [client (if custom-ssl-ctxt-factory (let [^ClientConnector connector (new ClientConnector)] (.setSslContextFactory connector custom-ssl-ctxt-factory) (new HttpClient (new HttpClientTransportDynamic connector (into-array ClientConnectionFactory$Info [HttpClientConnectionFactory/HTTP11])))) (if-let [ssl-ctxt-factory (:ssl-context-client-factory @(:state webserver-context))] (do (log/debug (i18n/trs "Proxy Using same config as server for ssl in proxy")) (let [connector (new ClientConnector)] (.setSslContextFactory connector ssl-ctxt-factory) (new HttpClient (new HttpClientTransportDynamic connector (into-array ClientConnectionFactory$Info [HttpClientConnectionFactory/HTTP11]))))) (do (log/debug (i18n/trs "Proxy using default http client with no SSL specification.")) (HttpClient.))))] (when request-buffer-size (.setRequestBufferSize client request-buffer-size)) client)) (createHttpClient [] (let [client (proxy-super createHttpClient) timeout (when idle-timeout (* 1000 idle-timeout))] (if (:follow-redirects options) (do (.setFollowRedirects client true) (.put (.getProtocolHandlers client) (RedirectProtocolHandler. client))) (.setFollowRedirects client false)) (when timeout (.setIdleTimeout client timeout)) client)) (sendProxyRequest [req proxy-response proxy-request] (when-let [callback-fn (:callback-fn options)] (callback-fn proxy-request req)) (proxy-super sendProxyRequest req proxy-response proxy-request))))) (schema/defn ^:always-validate register-endpoint! [state :- Atom endpoint-map :- Endpoint endpoint :- schema/Str] (swap! state update-in [:endpoints endpoint] #(if (nil? %) [endpoint-map] (conj % endpoint-map)))) (schema/defn ^:always-validate max-request-body-size-handler* [handler :- Handler max-size :- schema/Int] (proxy [Handler$Wrapper] [] (handle [^Request request ^Response response ^Callback callback] (let [request-size (.getLength request)] (if (> request-size max-size) (do (Response/writeError request response callback HttpServletResponse/SC_REQUEST_ENTITY_TOO_LARGE) true) (.handle handler request response callback)))))) (schema/defn ^:always-validate max-request-body-size-handler "Wrap a max-request-body-size handler around the supplied handler. The handler returns a 413 (request entity too large) error if the Content-Length HTTP header on the incoming request exceeds the value specified as the max-size parameter." [handler :- Handler max-size :- schema/Int] (doto (max-request-body-size-handler* handler max-size) (.setHandler handler))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Public (schema/defn ^:always-validate initialize-context :- ServerContext "Create a webserver-context which contains a Handler.Sequence and a ContextHandlerCollection which can accept the addition of new handlers before the webserver is started." [] ;; In Jetty 12, ContextHandlerCollection requires a varargs array of ContextHandler (let [^ContextHandlerCollection chc (ContextHandlerCollection. (into-array ContextHandler []))] {:handlers chc :state (atom {:endpoints {} :mbean-container nil :overrides-read-by-webserver false :overrides nil :ssl-context-server-factory nil :ssl-context-client-factory nil}) :server nil})) ; TODO move out of public (schema/defn ^:always-validate merge-webserver-overrides-with-options :- config/WebserverRawConfig "Merge any overrides made to the webserver config settings with the supplied options." [webserver-context :- ServerContext options :- config/WebserverRawConfig] {:post [(map? %)]} (let [overrides (:overrides (swap! (:state webserver-context) assoc :overrides-read-by-webserver true))] (doseq [key (keys overrides)] (log/info (i18n/trs "webserver config overridden for key ''{0}''" (name key)))) (merge options overrides))) (schema/defn ^:always-validate shutdown [{:keys [^Server server] :as webserver-context} :- ServerContext] (when-let [^MBeanContainer mbean-container (:mbean-container @(:state webserver-context))] (log/debug (i18n/trs "Cleaning up JMX MBean container")) (.destroy mbean-container) (swap! (:state webserver-context) assoc :mbean-container nil)) (when (started? webserver-context) (log/info (i18n/trs "Shutting down web server.")) (try (.stop server) (catch TimeoutException e (log/error e (i18n/trs "Web server failed to shut down gracefully in configured timeout period ({0}); cancelling remaining requests." (.getStopTimeout server)))) ;; This exception handling was added since we currently manually stop handlers within pcp-broker ;; for debugging purposes there - on shutdown if Jetty sees a STOPPED handler it throws an ;; ExecutionException with a IllegalStateException as it's cause and if unhandled shutdown ;; stops and the server goes into a FAILED state (catch ExecutionException e (log/error (.getCause e) (i18n/trs "Web server failed to shut down gracefully due to ExecutionException with inner exception of type {0}; cancelling remaining requests." (type (.getCause e)))))) (log/info (i18n/trs "Web server shutdown")))) (schema/defn ^:always-validate create-webserver :- ServerContext "Create a Jetty webserver according to the supplied options: :host - the hostname to listen on :port - the port to listen on (defaults to 8080) :ssl-host - the hostname to listen on for SSL connections :ssl-port - the SSL port to listen on (defaults to 8081) :max-threads - the maximum number of threads to use (default 100) :request-header-max-size - the maximum size of an HTTP request header (default 8192) :gzip-enable - whether or not gzip compression can be applied to the body of a response (default true) SSL may be configured via PEM files by providing all three of the following settings: :ssl-key - a PEM file containing the host's private key :ssl-cert - a PEM file containing the host's certificate or chain :ssl-ca-cert - a PEM file containing the CA certificate or via JKS keystore files by providing all four of the following settings: :keystore - the keystore to use for SSL connections :key-password - the password to the keystore :truststore - a truststore to use for SSL connections :trust-password - the password to the truststore Note that if SSL is being configured via PEM files, an optional :ssl-cert-chain setting may be included to specify a supplemental set of certificates to be appended to the first certificate from the :ssl-cert setting in order to construct the certificate chain. Other SSL settings: :client-auth - SSL client certificate authenticate, may be set to :need, :want or :none (defaults to :need) :cipher-suites - list of cryptographic ciphers to allow for incoming SSL connections :ssl-protocols - list of protocols to allow for incoming SSL connections" [webserver-context :- ServerContext options :- config/WebserverRawConfig] {:pre [(map? options)] :post [(started? %)]} (let [config (config/process-config (merge-webserver-overrides-with-options webserver-context options)) ^Server s (create-server webserver-context config) ;; In Jetty 12, Handler.Sequence requires handlers array or list ^Handler$Sequence hc (Handler$Sequence. (into-array Handler [])) logger (config/maybe-init-log-handler options)] (.addHandler hc (:handlers webserver-context)) (let [shutdown-timeout (* 1000 (:shutdown-timeout-seconds options config/default-shutdown-timeout-seconds)) maybe-zipped (if (:gzip-enable options true) (gzip-handler hc) hc) maybe-size-restricted (if-let [max-size (:request-body-max-size options)] (max-request-body-size-handler maybe-zipped max-size) maybe-zipped) maybe-logged (if logger (MDCHandler. maybe-size-restricted) maybe-size-restricted) graceful-handler (if (or (nil? shutdown-timeout) (pos? shutdown-timeout)) (GracefulHandler. maybe-logged) maybe-logged)] (.setHandler s graceful-handler) (if logger (do (log/info (i18n/trs "Using specified access logging")) (.setRequestLog s logger)) (do (log/info (i18n/trs "Using CustomRequestLog using extended NCSA format")) (.setRequestLog s (CustomRequestLog. (Slf4jRequestLogWriter.) CustomRequestLog/EXTENDED_NCSA_FORMAT)))) (when shutdown-timeout (log/info (i18n/trs "Server shutdown timeout set to {0} milliseconds" shutdown-timeout)) (.setStopTimeout s shutdown-timeout)) (assoc webserver-context :server s)))) (schema/defn ^:always-validate start-webserver! :- ServerContext "Creates and starts a webserver. Returns an updated context map containing the Server object." [webserver-context :- ServerContext config :- config/WebserverRawConfig] (let [webserver-context (create-webserver webserver-context config)] (log/info (i18n/trs "Starting web server.")) (try (.start (:server webserver-context)) (catch Exception e (log/error e (i18n/trs "Encountered error starting web server, so shutting down")) (shutdown webserver-context) (throw e))) webserver-context)) (schema/defn add-context-handler :- ContextHandler "Add a static content context handler (allow for customization of the context handler through jakarta.servlet.ServletContextListener implementations)" ([webserver-context :- ServerContext base-path :- schema/Str context-path :- schema/Str] (add-context-handler webserver-context base-path context-path nil {:follow-links? false :enable-trailing-slash-redirect? false})) ([webserver-context :- ServerContext base-path :- schema/Str context-path :- schema/Str context-listeners :- (schema/maybe [ServletContextListener]) options] ;; In Jetty 12, ServletContextHandler no longer takes parent Container in constructor (let [handler (doto (ServletContextHandler. context-path ServletContextHandler/NO_SESSIONS) (.setContextPath context-path)) follow-links? (:follow-links? options) enable-trailing-slash-redirect? (:enable-trailing-slash-redirect? options) normalize-request-uri? (:normalize-request-uri? options)] (.setBaseResource handler (.newResource (ResourceFactory/root) ^String base-path)) (.clearAliasChecks handler) ;; register servlet context listeners (if any) (when-not (nil? context-listeners) (dorun (map #(.addEventListener handler %) context-listeners))) ;; Control symlink behavior via DefaultServlet init params. In Jetty 12, ;; DefaultServlet registers alias checkers during init that override any ;; prior clearAliasChecks() call, so we must control it at the servlet level. (let [holder (ServletHolder. (DefaultServlet.))] (.setInitParameter holder "allowSymlinks" (str (boolean follow-links?))) (.setInitParameter holder "allowAliases" (str (boolean follow-links?))) (.addServlet handler holder "/")) (when normalize-request-uri? (normalized-uri-helpers/add-normalized-uri-filter-to-servlet-handler! handler)) (add-handler webserver-context handler enable-trailing-slash-redirect?)))) (defn- ring-servlet "Creates a servlet that wraps a Ring handler and includes the Jetty Response in the request map under the :response key for compatibility with code that needs access to the underlying Jetty response object. Returns a 404 response if the handler returns nil." [handler] (proxy [jakarta.servlet.http.HttpServlet] [] (service [^jakarta.servlet.http.HttpServletRequest request ^jakarta.servlet.http.HttpServletResponse response] ;; Force chunked transfer encoding. In ring-core 1.15.x, strings ;; are written directly to the underlying stream and teh stream is ;; closed without flushing, which lets Jetty use Content-Length framing. ;; With TLS 1.3, a NewSessionTicket may be sent immediately after the ;; response data. Ruby's net-http sees the pending TLS record and blocks ;; on a keep-alive check until timeout. Chunked encoding avoids this ;; because the ticket is consumed during body reading rather than ;; lingering in the TCP buffer. ;; ;; See https://github.com/OpenVoxProject/openvox-server/issues/197 for ;; more details. A fix in net-http is https://github.com/ruby/ruby/pull/6423 ;; but even if that gets merged into the version of Ruby we use in OpenVox, ;; older agents will be vulnerable to this issue. (.setHeader response "Transfer-Encoding" "chunked") (let [request-map (-> (servlet/build-request-map request) (assoc :response response)) response-map (handler request-map)] (servlet/update-servlet-response response (or response-map {:status 404})))))) (schema/defn ^:always-validate add-ring-handler :- ContextHandler "Adds a Ring handler to the webserver. Uses a servlet wrapper to properly integrate Ring handlers with Jetty 12's ee10 servlet environment." [webserver-context :- ServerContext handler :- (schema/pred ifn? 'ifn?) path :- schema/Str enable-trailing-slash-redirect? :- schema/Bool normalize-request-uri? :- schema/Bool] (let [servlet (ring-servlet handler) path (if (= "" path) "/" path) ctxt-handler (doto (ServletContextHandler. ServletContextHandler/NO_SESSIONS) (.setContextPath path) (.addServlet (ServletHolder. servlet) "/*"))] (when normalize-request-uri? (normalized-uri-helpers/add-normalized-uri-filter-to-servlet-handler! ctxt-handler)) (add-handler webserver-context ctxt-handler enable-trailing-slash-redirect?))) (schema/defn ^:always-validate add-servlet-handler :- ContextHandler [webserver-context :- ServerContext servlet :- Servlet path :- schema/Str servlet-init-params :- {schema/Any schema/Any} enable-trailing-slash-redirect? :- schema/Bool normalize-request-uri? :- schema/Bool] (let [holder (doto (ServletHolder. servlet) (.setInitParameters servlet-init-params)) handler (doto (ServletContextHandler. ServletContextHandler/SESSIONS) (.setContextPath path) (.addServlet holder "/*"))] (when normalize-request-uri? (normalized-uri-helpers/add-normalized-uri-filter-to-servlet-handler! handler)) (add-handler webserver-context handler enable-trailing-slash-redirect?))) (schema/defn ^:always-validate add-war-handler :- ContextHandler "Registers a WAR to Jetty. It takes two arguments: `[war path]`. - `war` is the file path or the URL to a WAR file - `path` is the URL prefix at which the WAR will be registered" [webserver-context :- ServerContext war :- schema/Str path :- schema/Str disable-redirects-no-slash? :- schema/Bool normalize-request-uri? :- schema/Bool] (let [handler (doto (WebAppContext.) (.setContextPath path) (.setWar war))] (when normalize-request-uri? (normalized-uri-helpers/add-normalized-uri-filter-to-servlet-handler! handler)) (add-handler webserver-context handler disable-redirects-no-slash?))) (schema/defn ^:always-validate add-proxy-route "Configures the Jetty server to proxy a given URL path to another host. `target` should be a map containing the keys :host, :port, and :path; where :path specifies the URL prefix to proxy to on the target host. `options` may contain the keys :scheme (legal values are :orig, :http, and :https), :ssl-config (value may be :use-server-config or a map containing :ssl-ca-cert, :ssl-cert, and :ssl-key), :rewrite-uri-callback-fn (a function taking two arguments, `[target-uri req]`, see README.md/#rewrite-uri-callback-fn), :callback-fn (a function taking two arguments, `[proxy-req req]`, see README.md/#callback-fn). " [webserver-context :- ServerContext target :- ProxyTarget path :- schema/Str options :- ProxyOptions disable-redirects-no-slash? :- schema/Bool] (let [target (update-in target [:path] remove-leading-slash)] ;; This call hardcodes a value of 'false' for the 'normalize-request-uri?' ;; parameter because the ProxyServlet already has its own logic for ;; normalizing request URIs as it proxies them through. Applying an ;; extra layer of normalization in front of the ProxyServlet might otherwise ;; cause requests to be proxied to an unintended URI. (add-servlet-handler webserver-context (proxy-servlet webserver-context target options) path {} disable-redirects-no-slash? false))) (schema/defn ^:always-validate get-registered-endpoints :- RegisteredEndpoints "Returns a map of registered endpoints for the given ServerContext. Each endpoint is registered as a key in the map, with its value being an array of maps, each representing a handler registered at that endpoint. Each of these maps contains the type of the handler under the :type key, and may contain additional information as well. When the value of :type is :context, the endpoint information will be an instance of ContextEndpoint. When the value of :type is :ring, the endpoint information will be an instance of RingEndpoint. When the value of :type is :servlet, the endpoint information will be an instance of ServletEndpoint. When the value of :type is :war, the endpoint information will be an instance of WarEndpoint. When the value of :type is :proxy, the endpoint information will be an instance of ProxyEndpoint." [webserver-context :- ServerContext] (:endpoints @(:state webserver-context))) (schema/defn ^:always-validate override-webserver-settings! :- config/WebserverRawConfig "Override the settings in the webserver section of the service's config file with the set of options in the supplied overrides map. The map should contain a key/value pair for each setting to be overridden. The name of the setting to override should be expressed as a Clojure keyword. For any setting expressed in the service config which is not overridden, the setting value from the config will be used. For example, the webserver config may contain: [webserver] ssl-host = 0.0.0.0 ssl-port = 9001 ssl-cert = mycert.pem ssl-key = mykey.pem ssl-ca-cert = myca.pem The following overrides map may be supplied as an argument to the function: {:ssl-port 9002 :ssl-cert \"myoverriddencert.pem\" :ssl-key \"myoverriddenkey.pem\"} The effective settings used during webserver startup will be: {:ssl-host \"0.0.0.0\" :ssl-port 9002 :ssl-cert \"myoverriddencert.pem\" :ssl-key \"myoverriddenkey.pem\" :ssl-ca-cert \"myca.pem\"} The overridden webserver settings will be considered only at the point the webserver is being started -- during the start lifecycle phase of the webserver service. For this reason, a call to this function must be made during a service's init lifecycle phase in order for the overridden settings to be considered. Only one call from a service may be made to this function during application startup. If a call is made to this function after webserver startup or after another call has already been made to this function (e.g., from other service), a java.lang.IllegalStateException will be thrown." [webserver-context :- ServerContext overrides :- config/WebserverRawConfig] ; Might be worth considering an implementation that only fails if the caller ; is trying to override a specific option that has been overridden already ; rather than blindly failing if an attempt is made to override any option. ; Could allow different services to override options that don't conflict with ; one another or for the same service to make multiple calls to this function ; for different settings. Hard to know, though, when one setting has an ; adverse effect on another without putting a bunch of key-specific semantic ; setting parsing in this implementation. (:overrides (swap! (:state webserver-context) #(cond (:overrides-read-by-webserver %) (if (nil? (:overrides %)) (throw (IllegalStateException. ^String (i18n/trs "overrides cannot be set because webserver has already processed the config"))) (throw (IllegalStateException. ^String (i18n/trs "overrides cannot be set because they have already been set and webserver has already processed the config")))) (nil? (:overrides %)) (assoc % :overrides overrides) :else (throw (IllegalStateException. ^String (i18n/trs "overrides cannot be set because they have already been set"))))))) (schema/defn ^:always-validate join [webserver-context :- ServerContext] {:pre [(started? webserver-context)]} (.join (:server webserver-context))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Service Implementation Helper Functions (defn start-server-single-default [context config] (let [default-context (:default (:jetty-servers context)) webserver (start-webserver! default-context config) server-context-list (assoc (:jetty-servers context) :default webserver)] (assoc context :jetty-servers server-context-list))) (defn start-server-multiple [context config] (let [context-seq (for [[server-id server-context] (:jetty-servers context)] [server-id (start-webserver! server-context (server-id config))])] (assoc context :jetty-servers (into {} context-seq)))) (defn get-server-context [service-context server-id] (let [server-id (if (nil? server-id) (:default-server service-context) server-id)] (when-not server-id (throw (IllegalArgumentException. ^String (i18n/trs "no server-id was specified for this operation and no default server was specified in the configuration")))) (server-id (:jetty-servers service-context)))) (defn get-default-server-from-config [config] (first (flatten (filter #(:default-server (second %)) config)))) (defn build-server-contexts [context config] (assoc context :jetty-servers (into {} (for [[server-id] config] [server-id (initialize-context)])) :default-server (get-default-server-from-config config))) (schema/defn ^:always-validate reload-crl-on-change! "Reload the CRL file used by the supplied ssl-context-factory whenever any changes to the file occur." [ssl-context-factory :- InternalSslContextFactory watcher :- (schema/protocol watch-protocol/Watcher)] (when-let [crl-path (.getCrlPath ssl-context-factory)] (let [normalized-crl-path (.getCanonicalPath (fs/file crl-path)) parent (fs/parent crl-path)] (log/debug (i18n/trs "Setting up file watcher on {0}" (.toString parent))) (watch-protocol/add-watch-dir! watcher (fs/parent crl-path)) (watch-protocol/add-callback! watcher (fn [events] (when (some #(and (:changed-path %) (= (.getCanonicalPath (:changed-path %)) normalized-crl-path)) events) (log/debug (i18n/trs "CRL reload triggered")) (.reload ssl-context-factory))))))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; Service Function Implementations (schema/defn ^:always-validate add-context-handler! [context base-path context-path options :- ContextHandlerOptions] (let [defaults {:context-listeners []} opts (merge defaults options) server-id (:server-id opts) context-listeners (:context-listeners opts) s (get-server-context context server-id) state (:state s) endpoint-map {:type :context :base-path base-path :context-listeners context-listeners} enable-redirect (get options :redirect-if-no-trailing-slash false) normalize-request-uri (get options :normalize-request-uri false)] (register-endpoint! state endpoint-map context-path) (add-context-handler s base-path context-path context-listeners {:follow-links? (:follow-links options) :enable-trailing-slash-redirect? enable-redirect :normalize-request-uri? normalize-request-uri}))) (schema/defn ^:always-validate init! [context config :- config/WebserverServiceRawConfig] (let [old-config (schema/check config/WebserverRawConfig config) new-config (schema/check config/MultiWebserverRawConfig config)] (cond (nil? old-config) (let [context (assoc context :jetty-servers {:default (initialize-context)} :default-server :default)] (doseq [content (:static-content config)] (add-context-handler! context (:resource content) (:path content) {:follow-links (true? (:follow-links content))})) context) (nil? new-config) (let [context (build-server-contexts context config)] (doseq [[server-id server-config] config content (:static-content server-config)] (add-context-handler! context (:resource content) (:path content) {:server-id server-id :follow-links (true? (:follow-links content))})) context)))) (schema/defn ^:always-validate start! [context config :- config/WebserverServiceRawConfig] (let [old-config (schema/check config/WebserverRawConfig config) new-config (schema/check config/MultiWebserverRawConfig config)] (cond (nil? old-config) (start-server-single-default context config) (nil? new-config) (start-server-multiple context config)))) (schema/defn ^:always-validate add-ring-handler! [context handler path options :- CommonOptions] (let [server-id (:server-id options) s (get-server-context context server-id) state (:state s) endpoint-map {:type :ring} enable-redirect (get options :redirect-if-no-trailing-slash false) normalize-request-uri (get options :normalize-request-uri false)] (register-endpoint! state endpoint-map path) (add-ring-handler s handler path enable-redirect normalize-request-uri))) (schema/defn ^:always-validate add-servlet-handler! [context servlet path options :- ServletHandlerOptions] (let [defaults {:servlet-init-params {}} opts (merge defaults options) server-id (:server-id opts) servlet-init-params (:servlet-init-params opts) s (get-server-context context server-id) state (:state s) endpoint-map {:type :servlet :servlet (type servlet)} enable-redirect (get options :redirect-if-no-trailing-slash false) normalize-request-uri (get options :normalize-request-uri false)] (register-endpoint! state endpoint-map path) (add-servlet-handler s servlet path servlet-init-params enable-redirect normalize-request-uri))) (schema/defn ^:always-validate add-war-handler! [context war path options :- CommonOptions] (let [server-id (:server-id options) s (get-server-context context server-id) state (:state s) endpoint-map {:type :war :war-path war} enable-redirect (get options :redirect-if-no-trailing-slash false) normalize-request-uri (get options :normalize-request-uri false)] (register-endpoint! state endpoint-map path) (add-war-handler s war path enable-redirect normalize-request-uri))) (schema/defn ^:always-validate add-proxy-route! [context target path options] (let [server-id (:server-id options) s (get-server-context context server-id) state (:state s) endpoint-map {:type :proxy :target-host (:host target) :target-port (:port target) :target-path (:path target)} enable-redirect (get options :redirect-if-no-trailing-slash false)] (register-endpoint! state endpoint-map path) (add-proxy-route s target path options enable-redirect))) jetty_service.clj000066400000000000000000000172361527232126200366250ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-service (:require [clojure.pprint :refer [pprint]] [clojure.tools.logging :as log] [puppetlabs.i18n.core :as i18n] [puppetlabs.trapperkeeper.config :as tk-config] [puppetlabs.trapperkeeper.core :refer [defservice]] [puppetlabs.trapperkeeper.services :refer [get-service maybe-get-service service-context]] [puppetlabs.trapperkeeper.services.protocols.filesystem-watch-service :as watch-protocol] [puppetlabs.trapperkeeper.services.webserver.jetty-config :as config] [puppetlabs.trapperkeeper.services.webserver.jetty-core :as core])) ;; TODO: this should probably be moved to a separate jar that can be used as ;; a dependency for all webserver service implementations (defprotocol WebserverService (add-context-handler [this base-path context-path] [this base-path context-path options]) (add-ring-handler [this handler path] [this handler path options]) (add-servlet-handler [this servlet path] [this servlet path options]) (add-war-handler [this war path] [this war path options]) (add-proxy-route [this target path] [this target path options]) (override-webserver-settings! [this overrides] [this server-id overrides]) (get-registered-endpoints [this] [this server-id]) (log-registered-endpoints [this] [this server-id]) (join [this] [this server-id])) (defservice jetty-service "Provides a Jetty web server as a service" WebserverService {:required [ConfigService] :optional [FilesystemWatchService]} (init [this context] (log/info (i18n/trs "Initializing web server(s).")) (let [config-service (get-service this :ConfigService) config (or (tk-config/get-in-config config-service [:webserver]) ;; Here for backward compatibility with existing projects (tk-config/get-in-config config-service [:jetty]) {})] (config/validate-config config) (core/init! context config))) (start [this context] (log/info (i18n/trs "Starting web server(s).")) (let [config-service (get-service this :ConfigService) config (or (tk-config/get-in-config config-service [:webserver]) ;; Here for backward compatibility with existing projects (tk-config/get-in-config config-service [:jetty]) {}) _ (log/debug (i18n/trs "Jetty server(s) starting with config: {0}" config)) started-context (core/start! context config)] ;; Log started server(s) configuration(s) for debugging purposes (doseq [started-server-context (:jetty-servers started-context)] ;; Server context data is in the form {:servername {:handlers , ... }} (let [server-name (name (first started-server-context)) started-server ^org.eclipse.jetty.server.Server (:server (second started-server-context)) connectors (.getConnectors started-server)] (log/debug (i18n/trs "Jetty server {0} started with context: {1}" server-name (with-out-str (pprint started-server-context)))) (log/debug (i18n/trs "Jetty server {0} started with URI: {1} Stop timeout: {2} milliseconds." server-name (.getURI started-server) (.getStopTimeout started-server))) (doseq [^org.eclipse.jetty.server.Connector connector connectors connector-index (range 0 (count connectors))] (let [connector-name (or (.getName connector) connector-index)] (log/debug (i18n/trs "Jetty server {0} started with connector {1} with idle-timeout {2}." server-name connector-name (.getIdleTimeout connector))) (log/debug (i18n/trs "Jetty server {0} started with connector {1} protocols: {2}." server-name connector-name (.getProtocols connector))))))) (if-let [filesystem-watcher-service (maybe-get-service this :FilesystemWatchService)] (let [watcher (watch-protocol/create-watcher filesystem-watcher-service {:recursive false})] (doseq [server (:jetty-servers started-context)] (when-let [ssl-context-factory (-> server second :state deref :ssl-context-server-factory)] (core/reload-crl-on-change! ssl-context-factory watcher))) (assoc started-context :watcher watcher)) started-context))) (stop [this context] (log/info (i18n/trs "Shutting down web server(s).")) (doseq [key (keys (:jetty-servers context))] (if-let [server (key (:jetty-servers context))] (core/shutdown server))) context) (add-context-handler [this base-path context-path] (core/add-context-handler! (service-context this) base-path context-path {})) (add-context-handler [this base-path context-path options] (core/add-context-handler! (service-context this) base-path context-path options)) (add-ring-handler [this handler path] (core/add-ring-handler! (service-context this) handler path {})) (add-ring-handler [this handler path options] (core/add-ring-handler! (service-context this) handler path options)) (add-servlet-handler [this servlet path] (core/add-servlet-handler! (service-context this) servlet path {})) (add-servlet-handler [this servlet path options] (core/add-servlet-handler! (service-context this) servlet path options)) (add-war-handler [this war path] (core/add-war-handler! (service-context this) war path {})) (add-war-handler [this war path options] (core/add-war-handler! (service-context this) war path options)) (add-proxy-route [this target path] (core/add-proxy-route! (service-context this) target path {})) (add-proxy-route [this target path options] (core/add-proxy-route! (service-context this) target path options)) (override-webserver-settings! [this overrides] (let [s (core/get-server-context (service-context this) nil)] (core/override-webserver-settings! s overrides))) (override-webserver-settings! [this server-id overrides] (let [s (core/get-server-context (service-context this) server-id)] (core/override-webserver-settings! s overrides))) (get-registered-endpoints [this] (let [s (core/get-server-context (service-context this) nil)] (core/get-registered-endpoints s))) (get-registered-endpoints [this server-id] (let [s (core/get-server-context (service-context this) server-id)] (core/get-registered-endpoints s))) (log-registered-endpoints [this] (log/info (str (get-registered-endpoints this)))) (log-registered-endpoints[this server-id] (log/info (str (get-registered-endpoints this server-id)))) (join [this] (let [s (core/get-server-context (service-context this) nil)] (core/join s))) (join [this server-id] (let [s (core/get-server-context (service-context this) server-id)] (core/join s)))) normalized_uri_helpers.clj000066400000000000000000000163561527232126200405150ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/src/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.normalized-uri-helpers (:require [clojure.string :as str] [puppetlabs.i18n.core :as i18n] [ring.util.jakarta.servlet :as servlet] [schema.core :as schema]) (:import (com.puppetlabs.trapperkeeper.services.webserver.jetty.utils HttpServletRequestWithAlternateRequestUri) (java.nio.charset StandardCharsets) (java.util EnumSet) (jakarta.servlet DispatcherType Filter) (jakarta.servlet.http HttpServletRequest HttpServletResponse) (org.eclipse.jetty.http HttpStatus) (org.eclipse.jetty.io Content$Sink) (org.eclipse.jetty.server Handler Handler$Wrapper Request Response) (org.eclipse.jetty.ee10.servlet FilterHolder ServletContextHandler) (org.eclipse.jetty.util Callback URIUtil))) (defn- contains-relative-segment? "Check if a decoded URI path contains relative path segments (. or ..). A segment is considered relative if it is exactly '.' or '..' when isolated between slashes (or at start/end of path)." [^String path] (let [segments (str/split path #"/")] (some #(or (= % ".") (= % "..")) segments))) (defn- normalize-uri-path-str "Normalize a URI path string. Returns the normalized path or throws IllegalArgumentException if the path contains relative segments." [^String uri-path] ;; Use Jetty's URIUtil.decodePath which handles percent-decoding and strips ;; path parameters (text after semicolons) (let [percent-decoded-uri-path (URIUtil/decodePath uri-path)] ;; Check for relative path segments (. or ..) (if (contains-relative-segment? percent-decoded-uri-path) (throw (IllegalArgumentException. ^String (i18n/trs "Invalid relative path (.. or .) in: {0}" percent-decoded-uri-path))) (URIUtil/compactPath percent-decoded-uri-path)))) (schema/defn ^:always-validate normalize-uri-path :- schema/Str "Return a 'normalized' version of the uri path represented on the incoming request. The 'normalization' consists of three steps: 1) URL (percent) decode the path, assuming any percent-encodings represent UTF-8 characters. An exception may be thrown if the request has malformed content, e.g., partially-formed percent-encoded characters like '%A%B'. If a semicolon character, U+003B, is found during the decoding process, it and any following characters will be removed from the decoded path. 2) Check the percent-decoded path for any relative path segments ('..' or '.'). An IllegalArgumentException is thrown if one or more segments are found. 3) Compact any repeated forward slash characters in a path." [request :- HttpServletRequest] (normalize-uri-path-str (.getRequestURI request))) (defn- send-bad-request-response "Send an HTTP 400 Bad Request response with the given message." [^Response response ^Callback callback ^String message] (.setStatus response HttpStatus/BAD_REQUEST_400) (let [bytes (.getBytes message StandardCharsets/UTF_8)] ;; In Jetty 12, use getHeaders().put() to set Content-Length (-> response (.getHeaders) (.put "Content-Length" (str (alength bytes)))) (Content$Sink/write response true bytes callback))) (schema/defn ^:always-validate normalize-uri-handler :- Handler$Wrapper "Create a `Handler.Wrapper` which validates request URIs and rejects requests with invalid URIs (containing relative path segments like '..' or '.') with an HTTP 400 (Bad Request) response. Note: In Jetty 12, this handler operates at the core handler level and validates URIs. For servlet contexts where the request needs to be wrapped with a normalized URI, use `add-normalized-uri-filter-to-servlet-handler!` to add a servlet filter that provides the wrapped HttpServletRequest." [] (proxy [Handler$Wrapper] [] (handle [^Request request ^Response response ^Callback callback] (if-let [handler (.getHandler ^Handler$Wrapper this)] (try (let [uri-path (-> request (.getHttpURI) (.getPath))] ;; Validate the URI path - throws if invalid (normalize-uri-path-str uri-path) ;; URI is valid, pass to downstream handler (.handle handler request response callback)) (catch IllegalArgumentException ex ;; Invalid URI - return 400 Bad Request (send-bad-request-response response callback (.getMessage ex)) true)) false)))) (schema/defn ^:always-validate normalized-uri-filter :- Filter "Create a servlet filter which provides a normalized request URI on to its downstream consumers for an incoming request. The normalized URI would be returned for a 'getRequestURI' call on the HttpServletRequest parameter. Normalization is done per the rules described in the `normalize-uri-path` function. If an error is encountered during request URI normalization, an HTTP 400 (Bad Request) response is returned rather than the request being passed on its downstream consumers." [] (reify Filter (init [_ _]) (doFilter [_ request response chain] ;; The method signature for a servlet filter has a 'request' of the ;; more generic 'ServletRequest' and 'response' of the more generic ;; 'ServletResponse'. While we practically shouldn't see anything ;; but the more specific Http types for each, this code explicitly ;; checks to see that the requests are Http types as the URI ;; normalization would be irrelevant for other types. (if (and (instance? HttpServletRequest request) (instance? HttpServletResponse response)) (if-let [normalized-uri (try (normalize-uri-path request) (catch IllegalArgumentException ex (servlet/update-servlet-response response {:status 400 :body (.getMessage ex)}) nil))] (.doFilter chain (HttpServletRequestWithAlternateRequestUri. request normalized-uri) response)) (.doFilter chain request response))) (destroy [_]))) (schema/defn ^:always-validate add-normalized-uri-filter-to-servlet-handler! "Adds a servlet filter to the servlet handler which provides a normalized request URI on to its downstream consumers for an incoming request." [handler :- ServletContextHandler] (let [filter-holder (FilterHolder. (normalized-uri-filter))] (.addFilter handler filter-holder "/*" (EnumSet/of DispatcherType/REQUEST)))) (schema/defn ^:always-validate handler-maybe-wrapped-with-normalized-uri :- Handler "If the supplied `normalize-request-uri?` parameter is 'true', return a handler that validates request URIs and rejects invalid ones. Note: In Jetty 12, this wrapper validates URIs at the core handler level. For servlet contexts that need the actual normalized URI passed downstream, also use `add-normalized-uri-filter-to-servlet-handler!` to add a filter." [handler :- Handler normalize-request-uri? :- schema/Bool] (if normalize-request-uri? (doto (normalize-uri-handler) (.setHandler handler)) handler)) OpenVoxProject-trapperkeeper-webserver-8a905f4/test/000077500000000000000000000000001527232126200226335ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/000077500000000000000000000000001527232126200234035ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/000077500000000000000000000000001527232126200255625ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/000077500000000000000000000000001527232126200304335ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/000077500000000000000000000000001527232126200322565ustar00rootroot00000000000000webrouting/000077500000000000000000000000001527232126200343645ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/serviceswebrouting_service_handlers_test.clj000066400000000000000000000263301527232126200437060ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-handlers-test (:import (jakarta.servlet.http HttpServletResponse) (servlet SimpleServlet)) (:require [clojure.test :refer :all] [schema.test :as schema-test] [puppetlabs.trapperkeeper.services :as tk-services] [puppetlabs.trapperkeeper.services.webrouting.webrouting-service :refer :all] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service]] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.testutils.webrouting.common :refer :all] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (def dev-resources-dir "./dev-resources/") (defprotocol TestDummy (dummy [this])) (tk-services/defservice test-dummy TestDummy [] (dummy [this] "This is a dummy function. Please ignore.")) (def webrouting-plaintext-multiserver-config {:webserver {:bar {:port 8080 :default-server true} :foo {:port 9000}} :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-handlers-test/test-dummy {:route "/foo" :server "foo"}}}) (def webrouting-plaintext-multiroute-config {:webserver {:port 8080} :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-handlers-test/test-dummy {:quux "/foo" :foo "/bar"}}}) (deftest add-context-handler-test (with-test-logging (testing "static content context with web routing" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-config (let [s (get-service app :WebroutingService) add-context-handler (partial add-context-handler s) resource "logback.xml" svc (get-service app :TestDummy)] (add-context-handler svc dev-resources-dir) (let [response (http-get (str "http://localhost:8080/foo/" resource))] (is (= (:status response) 200)) (is (= (:body response) (slurp (str dev-resources-dir resource)))))))) (testing "static content context with multiple routes" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-multiroute-config (let [s (get-service app :WebroutingService) add-context-handler (partial add-context-handler s) resource "logback.xml" svc (get-service app :TestDummy)] (add-context-handler svc dev-resources-dir {:route-id :quux}) (add-context-handler svc dev-resources-dir {:route-id :foo}) (let [response (http-get (str "http://localhost:8080/foo/" resource))] (is (= (:status response) 200)) (is (= (:body response) (slurp (str dev-resources-dir resource))))) (let [response (http-get (str "http://localhost:8080/bar/" resource))] (is (= (:status response) 200)) (is (= (:body response) (slurp (str dev-resources-dir resource)))))))))) (deftest ring-handler-test-web-routing (with-test-logging (testing "ring request over http succeeds with web-routing" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-config (let [s (get-service app :WebroutingService) add-ring-handler (partial add-ring-handler s) body "Hi World" ring-handler (fn [req] {:status 200 :body body}) svc (get-service app :TestDummy)] (add-ring-handler svc ring-handler) (let [response (http-get "http://localhost:8080/foo")] (is (= (:status response) 200)) (is (= (:body response) body)))))) (testing "ring request over http succeeds with multiple web-routes" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-multiroute-config (let [s (get-service app :WebroutingService) add-ring-handler (partial add-ring-handler s) body "Hi World" ring-handler (fn [req] {:status 200 :body body}) svc (get-service app :TestDummy)] (add-ring-handler svc ring-handler {:route-id :quux}) (add-ring-handler svc ring-handler {:route-id :foo}) (let [response (http-get "http://localhost:8080/foo")] (is (= (:status response) 200)) (is (= (:body response) body))) (let [response (http-get "http://localhost:8080/bar")] (is (= (:status response) 200)) (is (= (:body response) body)))))))) (deftest servlet-test-web-routing (with-test-logging (testing "request to servlet over http succeeds with web routing" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-config (let [s (get-service app :WebroutingService) add-servlet-handler (partial add-servlet-handler s) body "Hey there" servlet (SimpleServlet. body "text/html" false) svc (get-service app :TestDummy)] (add-servlet-handler svc servlet) (let [response (http-get "http://localhost:8080/foo")] (is 200 (= (:status response))) (is "text/html;charset=utf-8" (= (get-in response [:headers "content-type"]))) (is body (= (:body response))))))) (testing "request to servlet over http succeeds with multiple web routes" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-multiroute-config (let [s (get-service app :WebroutingService) add-servlet-handler (partial add-servlet-handler s) body "Hey there" servlet (SimpleServlet. body "text/html" false) svc (get-service app :TestDummy)] (add-servlet-handler svc servlet {:route-id :quux}) (add-servlet-handler svc servlet {:route-id :foo}) (let [response (http-get "http://localhost:8080/foo")] (is (= (:status response) 200)) (is "text/html;charset=utf-8" (= (get-in response [:headers "content-type"]))) (is (= (:body response) body))) (let [response (http-get "http://localhost:8080/bar")] (is (= (:status response) 200)) (is "text/html;charset=utf-8" (= (get-in response [:headers "content-type"]))) (is (= (:body response) body)))))))) (deftest war-test-web-routing (with-test-logging (testing "WAR support with web routing" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-config (let [s (get-service app :WebroutingService) add-war-handler (partial add-war-handler s) war "helloWorld.war" svc (get-service app :TestDummy)] (add-war-handler svc (str dev-resources-dir war)) (let [response (http-get "http://localhost:8080/foo/hello")] (is (= (:status response) 200)) (is (= (:body response) "\nHello World Servlet\nHello World!!\n\n")))))) (testing "WAR support with multiple web routes" (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-multiroute-config (let [s (get-service app :WebroutingService) add-war-handler (partial add-war-handler s) war "helloWorld.war" svc (get-service app :TestDummy)] (add-war-handler svc (str dev-resources-dir war) {:route-id :quux}) (add-war-handler svc (str dev-resources-dir war) {:route-id :foo}) (let [response (http-get "http://localhost:8080/foo/hello")] (is (= (:status response) 200)) (is (= (:body response) "\nHello World Servlet\nHello World!!\n\n"))) (let [response (http-get "http://localhost:8080/bar/hello")] (is (= (:status response) 200)) (is (= (:body response) "\nHello World Servlet\nHello World!!\n\n")))))))) (deftest endpoints-test-web-routing (testing (str "get-registered-endpoints and log-registered-endpoints are " "successful with the web-routing service") (with-test-logging (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-config (let [s (get-service app :WebroutingService) get-registered-endpoints (partial get-registered-endpoints s) log-registered-endpoints (partial log-registered-endpoints s) add-ring-handler (partial add-ring-handler s) ring-handler (fn [req] {:status 200 :body "Hi world"}) svc (get-service app :TestDummy)] (add-ring-handler svc ring-handler) (let [endpoints (get-registered-endpoints)] (is (= endpoints {"/foo" [{:type :ring}]}))) (log-registered-endpoints) (is (logged? #"^\{\"\/foo\" \[\{:type :ring}\]\}$")) (is (logged? #"^\{\"\/foo\" \[\{:type :ring}\]\}$" :info))))))) (deftest ring-handler-include-response (with-test-logging (with-app-with-config app [jetty-service webrouting-service test-dummy] webrouting-plaintext-config (let [handler-args (atom nil)] (add-ring-handler (get-service app :WebroutingService) (get-service app :TestDummy) (fn [& args] (reset! handler-args args) {:status 200 :body "yep"})) (let [{:keys [status body]} (http-get "http://localhost:8080/foo")] (is (= 200 status)) (is (= "yep" body)) (is (= 1 (count @handler-args))) ;; response is included by default (HttpServletResponse in Jetty 12 ee10) (is (instance? HttpServletResponse (-> @handler-args first :response)))))))) webrouting_service_override_settings_test.clj000066400000000000000000000112271527232126200456440ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-override-settings-test (:require [clojure.test :refer :all] [puppetlabs.trapperkeeper.services :as tk-services] [puppetlabs.trapperkeeper.services.webrouting.webrouting-service :refer :all] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service]] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.testutils.webrouting.common :refer :all] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [schema.test :as schema-test] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (def dev-resources-dir "./dev-resources/") (def dev-resources-config-dir (str dev-resources-dir "config/jetty/")) (defprotocol TestDummy (dummy [this])) (tk-services/defservice test-dummy TestDummy [] (dummy [this] "This is a dummy function. Please ignore.")) (def webrouting-plaintext-override-config {:webserver {:port 8080} :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-override-settings-test/test-dummy "/foo"}}) (deftest test-override-webserver-settings!-with-web-routing (let [ssl-port 9001 overrides {:ssl-port ssl-port :ssl-host "0.0.0.0" :ssl-cert (str dev-resources-config-dir "ssl/certs/localhost.pem") :ssl-key (str dev-resources-config-dir "ssl/private_keys/localhost.pem") :ssl-ca-cert (str dev-resources-config-dir "ssl/certs/ca.pem") :ssl-crl-path (str dev-resources-config-dir "ssl/crls/crls_none_revoked.pem")}] (testing "config override of all SSL settings before webserver starts is successful with web-routing" (let [override-result (atom nil) service1 (tk-services/service [[:WebroutingService override-webserver-settings!]] (init [this context] (reset! override-result (override-webserver-settings! overrides)) context))] (with-test-logging (with-app-with-config app [jetty-service webrouting-service service1 test-dummy] webrouting-plaintext-override-config (let [s (get-service app :WebroutingService) add-ring-handler (partial add-ring-handler s) body "Hi World" path "/foo" ring-handler (fn [req] {:status 200 :body body}) svc (get-service app :TestDummy)] (add-ring-handler svc ring-handler) (let [response (http-get (format "https://localhost:%d%s/" ssl-port path) default-options-for-https-client)] (is (= (:status response) 200) "Unsuccessful http response code ring handler response.") (is (= (:body response) body) "Unexpected body in ring handler response.")))) (is (logged? #"^webserver config overridden for key 'ssl-port'") "Didn't find log message for override of 'ssl-port'") (is (logged? #"^webserver config overridden for key 'ssl-host'") "Didn't find log message for override of 'ssl-host'") (is (logged? #"^webserver config overridden for key 'ssl-cert'") "Didn't find log message for override of 'ssl-cert'") (is (logged? #"^webserver config overridden for key 'ssl-key'") "Didn't find log message for override of 'ssl-key'") (is (logged? #"^webserver config overridden for key 'ssl-ca-cert'") "Didn't find log message for override of 'ssl-ca-cert'") (is (logged? #"^webserver config overridden for key 'ssl-crl-path'") "Didn't find log message for override of 'ssl-crl-path'")) (is (= overrides @override-result) "Unexpected response to override-webserver-settings! call."))))) webrouting_service_proxy_test.clj000066400000000000000000000103201527232126200432570ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-proxy-test (:require [clojure.test :refer :all] [puppetlabs.trapperkeeper.services.webrouting.webrouting-service :refer :all] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service]] [puppetlabs.trapperkeeper.testutils.webrouting.common :refer :all] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [puppetlabs.trapperkeeper.services :as tk-services] [schema.test :as schema-test] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (defprotocol DummyService1 (dummy1 [this])) (defprotocol DummyService2 (dummy2 [this])) (tk-services/defservice dummy-service1 DummyService1 [] (dummy1 [this] "This is a dummy function. Please ignore.")) (tk-services/defservice dummy-service2 DummyService2 [] (dummy2 [this] "This is a dummy function. Please ignore.")) (defmacro with-target-and-proxy-servers [{:keys [target proxy proxy-config proxy-opts]} & body] `(with-test-logging (with-app-with-config proxy-target-app# [jetty-service webrouting-service dummy-service1] {:webserver ~target :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-proxy-test/dummy-service1 "/hello"}} (let [target-webserver# (get-service proxy-target-app# :WebroutingService) svc# (get-service proxy-target-app# :DummyService1)] (add-ring-handler target-webserver# svc# (fn [req#] (if (= "/hello/world" (:uri req#)) {:status 200 :body (str "Hello, World!" ((:headers req#) "x-fancy-proxy-header"))} {:status 404 :body "D'oh"})))) (with-app-with-config proxy-app# [jetty-service webrouting-service dummy-service2] {:webserver ~proxy :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-proxy-test/dummy-service2 {:bar "/hello-proxy" :foo "/goodbye-proxy"}}} (let [proxy-webserver# (get-service proxy-app# :WebroutingService) svc# (get-service proxy-app# :DummyService2)] (if ~proxy-opts (add-proxy-route proxy-webserver# svc# ~proxy-config ~proxy-opts) (add-proxy-route proxy-webserver# svc# ~proxy-config {:route-id :bar}))) ~@body)))) (deftest proxy-test-web-routing (testing "proxy support with web routing" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"}} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "basic https proxy support with multiple web routes" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:route-id :foo}} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/goodbye-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!")))))) webrouting_service_test.clj000066400000000000000000000161701527232126200420270ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test (:require [clojure.test :refer :all] [puppetlabs.kitchensink.testutils.fixtures :as ks-test-fixtures] [puppetlabs.trapperkeeper.app :as tk-app] [puppetlabs.trapperkeeper.services :as tk-services] [puppetlabs.trapperkeeper.services.webrouting.webrouting-service :refer :all] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service]] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [puppetlabs.trapperkeeper.testutils.webrouting.common :refer :all] [puppetlabs.trapperkeeper.testutils.webserver :as testutils] [schema.test :as schema-test])) (use-fixtures :once ks-test-fixtures/with-no-jvm-shutdown-hooks schema-test/validate-schemas testutils/assert-clean-shutdown) (defprotocol TestService (hello [this])) (defprotocol TestService2) (defprotocol TestService3) (defprotocol NotReal (dummy [this])) (tk-services/defservice test-service TestService [[:WebroutingService add-ring-handler]] (init [this context] (let [body "Hello World!" ring-handler (fn [req] {:status 200 :body body})] (add-ring-handler this ring-handler {:route-id :bert}) (add-ring-handler this ring-handler {:route-id :bar}) (add-ring-handler this ring-handler {:route-id :baz}) (add-ring-handler this ring-handler {:route-id :quux})) context) (hello [this] "This is a dummy function. Please disregard.")) (tk-services/defservice test-service-2 TestService2 [[:WebroutingService add-ring-handler]]) (tk-services/defservice test-service-3 TestService3 [[:WebroutingService add-ring-handler]]) (tk-services/defservice not-real NotReal [] (dummy [this] "This is a dummy function. Please disregard.")) (def webrouting-plaintext-multiserver-multiroute-config {:webserver {:bar {:port 8080 :default-server true} :foo {:port 9000}} :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test/test-service {:bert "/foo" :bar "/bar" :baz {:route "/foo" :server "foo"} :quux {:route "/bar" :server "foo"}} :puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test/test-service-2 "/foo" :puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test/test-service-3 {:route "/foo" :server "foo"}}}) (def no-default-config {:webserver {:bar {:port 8080} :foo {:port 9000}} :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test/test-service-2 "/foo"}}) (def default-route-config {:webserver {:port 8080} :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test/test-service-2 {:default "/foo" :bar "/bar"}}}) (deftest webrouting-service-test (with-test-logging (testing "Other services can successfully use webrouting service" (with-app-with-config app [jetty-service webrouting-service test-service] webrouting-plaintext-multiserver-multiroute-config (let [response (http-get "http://localhost:8080/foo/")] (is (= (:status response) 200)) (is (= (:body response) "Hello World!"))) (let [response (http-get "http://localhost:8080/bar/")] (is (= (:status response) 200)) (is (= (:body response) "Hello World!"))) (let [response (http-get "http://localhost:9000/foo/")] (is (= (:status response) 200)) (is (= (:body response) "Hello World!"))) (let [response (http-get "http://localhost:9000/bar/")] (is (= (:status response) 200)) (is (= (:body response) "Hello World!"))))) (testing "Error occurs when specifying service that does not exist in config file" (with-app-with-config app [jetty-service webrouting-service not-real] webrouting-plaintext-config (let [s (tk-app/get-service app :WebroutingService) add-ring-handler (partial add-ring-handler s) body "Hello World!" ring-handler (fn [req] {:status 200 :body body}) svc (tk-app/get-service app :NotReal)] (is (thrown? IllegalArgumentException (add-ring-handler svc ring-handler)))))) (testing "Error occurs when endpoints don't have servers and no default is set" (with-app-with-config app [jetty-service webrouting-service test-service-2] no-default-config (let [s (tk-app/get-service app :WebroutingService) add-ring-handler (partial add-ring-handler s) body "Hello World!" ring-handler (fn [req] {:status 200 :body body}) svc (tk-app/get-service app :TestService2)] (is (thrown? IllegalArgumentException (add-ring-handler svc ring-handler)))))) (testing "Error occurs when not specifying a route-id for a multi-route config" (with-app-with-config app [jetty-service webrouting-service test-service-2] default-route-config (let [s (tk-app/get-service app :WebroutingService) svc (tk-app/get-service app :TestService2) add-ring-handler (partial add-ring-handler s) ring-handler (fn [req] {:status 200 :body ""})] (is (thrown? IllegalArgumentException (add-ring-handler svc ring-handler)))))) (testing "Can access route-ids for a service" (with-app-with-config app [jetty-service webrouting-service test-service test-service-2] webrouting-plaintext-multiserver-multiroute-config (let [s (tk-app/get-service app :WebroutingService) svc (tk-app/get-service app :TestService) svc2 (tk-app/get-service app :TestService2) get-route (partial get-route s)] (is (= "/foo" (get-route svc :bert))) (is (= "/bar" (get-route svc :bar))) (is (= "/foo" (get-route svc :baz))) (is (= "/bar" (get-route svc :quux))) (is (= "/foo" (get-route svc2)))))) (testing "Can access server for a service" (with-app-with-config app [jetty-service webrouting-service test-service test-service-2 test-service-3] webrouting-plaintext-multiserver-multiroute-config (let [s (tk-app/get-service app :WebroutingService) svc (tk-app/get-service app :TestService) svc2 (tk-app/get-service app :TestService2) svc3 (tk-app/get-service app :TestService3) get-server (partial get-server s)] (is (= "foo" (get-server svc :baz))) (is (= nil (get-server svc :bar))) (is (= nil (get-server svc2))) (is (= "foo" (get-server svc3)))))))) OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver/000077500000000000000000000000001527232126200342625ustar00rootroot00000000000000jetty_config_test.clj000066400000000000000000000454521527232126200404320ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-config-test (:import (clojure.lang ExceptionInfo) (java.util Arrays) (com.puppetlabs.ssl_utils SSLUtils)) (:require [clojure.test :refer :all] [clojure.java.io :refer [resource]] [me.raynes.fs :as fs] [puppetlabs.ssl-utils.core :as ssl] [puppetlabs.kitchensink.core :as ks] [puppetlabs.trapperkeeper.services.webserver.jetty-config :refer :all] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [puppetlabs.trapperkeeper.services.webserver.jetty-core :as jetty] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service add-ring-handler]] [puppetlabs.trapperkeeper.app :as tk-app] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.webserver.common :refer [http-get]] [schema.test :as schema-test] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (defn valid-ssl-pem-config [] {:ssl-cert "./dev-resources/config/jetty/ssl/certs/localhost.pem" :ssl-key "./dev-resources/config/jetty/ssl/private_keys/localhost.pem" :ssl-ca-cert "./dev-resources/config/jetty/ssl/certs/ca.pem"}) (defn valid-ssl-keystore-config [] {:keystore (str "./dev-resources/config/jetty/ssl/keystore." (if (SSLUtils/isFIPS) "bcfks" "jks")) :truststore (str "./dev-resources/config/jetty/ssl/truststore." (if (SSLUtils/isFIPS) "bcfks" "jks")) :key-password "Kq8lG9LkISky9cDIYysiadxRx" :trust-password "Kq8lG9LkISky9cDIYysiadxRx"}) (defn munge-actual-http-config [config] (process-config config)) (defn munge-expected-common-config [expected scheme] (-> expected (update-in [:max-threads] identity) (update-in [:queue-max-size] identity) (update-in [:jmx-enable] (fnil ks/parse-bool default-jmx-enable)) (update-in [scheme :request-header-max-size] identity) (update-in [scheme :idle-timeout-milliseconds] identity) (update-in [scheme :acceptor-threads] identity) (update-in [scheme :selector-threads] identity))) (defn munge-expected-http-config [expected] (munge-expected-common-config expected :http)) (defn munge-actual-https-config [config] (let [actual (process-config config)] (-> actual (update-in [:https] dissoc :keystore-config)))) (defn munge-expected-https-config [expected] (-> (munge-expected-common-config expected :https) (update-in [:https :cipher-suites] (fnil identity (if (SSLUtils/isFIPS) acceptable-ciphers-fips acceptable-ciphers))) (update-in [:https :protocols] (fnil identity default-protocols)) (update-in [:https :client-auth] (fnil identity default-client-auth)) (update-in [:https :allow-renegotiation] (fnil identity default-allow-renegotiation)) (update-in [:https :sni-required] (fnil identity default-sni-required)) (update-in [:https :ssl-crl-path] identity))) (deftest process-config-http-test (testing "process-config successfully builds a WebserverConfig for plaintext connector" (is (= (munge-actual-http-config {:port 8000}) (munge-expected-http-config {:http {:host default-host :port 8000}}))) (is (= (munge-actual-http-config {:port 8000 :host "foo.local"}) (munge-expected-http-config {:http {:host "foo.local" :port 8000}}))) (is (= (munge-actual-http-config {:host "foo.local"}) (munge-expected-http-config {:http {:host "foo.local" :port default-http-port}}))) (is (= (munge-actual-http-config {:port 8000 :request-header-max-size 16192}) (munge-expected-http-config {:http {:host default-host :port 8000 :request-header-max-size 16192}}))) (is (= (munge-actual-http-config {:port 8000 :max-threads 500}) (munge-expected-http-config {:http {:host default-host :port 8000} :max-threads 500}))) (is (= (munge-actual-http-config {:port 8000 :queue-max-size 123}) (munge-expected-http-config {:http {:host default-host :port 8000} :queue-max-size 123}))) (is (= (munge-actual-http-config {:port 8000 :idle-timeout-milliseconds 6000}) (munge-expected-http-config {:http {:host default-host :port 8000 :idle-timeout-milliseconds 6000}}))) (is (= (munge-actual-http-config {:port 8000 :acceptor-threads 32}) (munge-expected-http-config {:http {:host default-host :port 8000 :acceptor-threads 32}}))) (is (= (munge-actual-http-config {:port 8000 :selector-threads 52}) (munge-expected-http-config {:http {:host default-host :port 8000 :selector-threads 52}}))))) (deftest process-config-https-test (testing "process-config successfully builds a WebserverConfig for ssl connector" (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local"})) (munge-expected-https-config {:https {:host "foo.local" :port default-https-port}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-port 8001})) (munge-expected-https-config {:https {:host default-host :port 8001}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001})) (munge-expected-https-config {:https {:host "foo.local" :port 8001}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :request-header-max-size 16192})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :request-header-max-size 16192}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :max-threads 93})) (munge-expected-https-config {:https {:host "foo.local" :port 8001} :max-threads 93}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :queue-max-size 99})) (munge-expected-https-config {:https {:host "foo.local" :port 8001} :queue-max-size 99}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :idle-timeout-milliseconds 4200})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :idle-timeout-milliseconds 4200}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :ssl-selector-threads 4242})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :selector-threads 4242}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :allow-renegotiation true})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :allow-renegotiation true}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :allow-renegotiation false})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :allow-renegotiation false}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :sni-required true})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :sni-required true}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :sni-required false})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :sni-required false}}))) (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :ssl-port 8001 :ssl-acceptor-threads 9193})) (munge-expected-https-config {:https {:host "foo.local" :port 8001 :acceptor-threads 9193}}))))) (deftest process-config-jks-test (testing "jks ssl config" (is (= (munge-actual-https-config (merge (valid-ssl-keystore-config) {:ssl-port 8001})) (munge-expected-https-config {:https {:host default-host :port 8001}}))))) (deftest process-config-ciphers-test (testing "cipher suites" (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-port 8001 :cipher-suites ["FOO" "BAR"]})) (munge-expected-https-config {:https {:host default-host :port 8001 :cipher-suites ["FOO" "BAR"]}})))) (testing "cipher suites as a comma and space-separated string" (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-port 8001 :cipher-suites "FOO, BAR"})) (munge-expected-https-config {:https {:host default-host :port 8001 :cipher-suites ["FOO" "BAR"]}}))))) (deftest process-config-protocols-test (testing "protocols" (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-port 8001 :ssl-protocols ["FOO" "BAR"]})) (munge-expected-https-config {:https {:host default-host :port 8001 :protocols ["FOO" "BAR"]}})))) (testing "protocols as a comma and space-separated string" (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-port 8001 :ssl-protocols "FOO, BAR"})) (munge-expected-https-config {:https {:host default-host :port 8001 :protocols ["FOO" "BAR"]}}))))) (deftest process-config-crl-test (testing "ssl-crl-path" (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-port 8001 :ssl-crl-path "./dev-resources/config/jetty/ssl/certs/ca.pem"})) (munge-expected-https-config {:https {:host default-host :port 8001 :ssl-crl-path "./dev-resources/config/jetty/ssl/certs/ca.pem"}}))))) (deftest process-config-client-auth-test (testing "client auth" (letfn [(get-client-auth [config] (-> config (merge (valid-ssl-pem-config)) process-config (get-in [:https :client-auth])))] (testing "configure-web-server should set client-auth to a value of :need if not specified in options" (is (= :need (get-client-auth {:ssl-port 8001})))) (testing "configure-web-server should convert client-auth string to appropriate corresponding keyword value in configure-web-server options" (is (= :need (get-client-auth {:ssl-port 8081 :client-auth "need"}))) (is (= :want (get-client-auth {:ssl-port 8081 :client-auth "want"}))) (is (= :none (get-client-auth {:ssl-port 8081 :client-auth "none"})))) (testing "configure-web-server should throw IllegalArgumentException if an unsupported value is specified for the client-auth option" (is (thrown-with-msg? java.lang.IllegalArgumentException #"Unexpected value found for client auth config option: bogus. Expected need, want, or none." (get-client-auth {:ssl-port 8081 :client-auth "bogus"}))))))) (deftest process-config-http-plus-https-test (testing "process-config successfully builds a WebserverConfig for plaintext+ssl" (is (= (munge-actual-https-config (merge (valid-ssl-pem-config) {:ssl-host "foo.local" :port 8000})) (munge-expected-https-config {:http {:host default-host :port 8000 :request-header-max-size nil :idle-timeout-milliseconds nil :acceptor-threads nil :selector-threads nil} :https {:host "foo.local" :port default-https-port}}))))) (deftest process-config-invalid-test (testing "process-config fails for invalid server config" (are [config] (thrown? ExceptionInfo (process-config config)) {:port "foo"} {:port 8000 :badkey "hi"})) (testing "process-config fails for incomplete ssl context config" (are [config] (thrown? IllegalArgumentException (process-config config)) {} {:ssl-port 8001} {:ssl-port 8001 :ssl-host "foo.local"} {:ssl-host "foo.local"} (valid-ssl-pem-config) (merge {:ssl-port 8001} (dissoc (valid-ssl-pem-config) :ssl-key)) (merge {:ssl-port 8001} (dissoc (valid-ssl-keystore-config) :keystore)))) (testing "should warn if both keystore-based and PEM-based SSL settings are found" (with-test-logging (process-config (merge {:ssl-port 8001} (valid-ssl-pem-config) (valid-ssl-keystore-config))) (is (logged? #"Found settings for both keystore-based and PEM-based SSL"))))) (defn- validate-cert-lists-equal [pem-with-expected-certs ssl-cert ssl-cert-chain] (let [expected-certs (ssl/pem->certs pem-with-expected-certs) actual-certs (construct-ssl-x509-cert-chain ssl-cert ssl-cert-chain)] (is (= (count expected-certs) (count actual-certs)) "Number of expected certs do not match number of actual certs") (dotimes [n (count expected-certs)] (is (Arrays/equals (.getEncoded (nth expected-certs n)) (.getEncoded (nth actual-certs n))) (str "Expected cert # " n " from does not match actual cert"))))) (deftest construct-ssl-x509-cert-chain-test (testing "non-existent ssl-cert throws expected exception" (let [tmp-file (ks/temp-file)] (fs/delete tmp-file) (is (thrown-with-msg? IllegalArgumentException #"^Unable to open 'ssl-cert' file:" (construct-ssl-x509-cert-chain (.getAbsolutePath tmp-file) nil))))) (testing "no content in ssl-cert throws expected exception" (let [tmp-file (ks/temp-file)] (is (thrown-with-msg? Exception #"^No certs found in 'ssl-cert' file:" (construct-ssl-x509-cert-chain (.getAbsolutePath tmp-file) nil))))) (testing "non-existent ssl-cert-chain throws expected exception" (let [tmp-file (ks/temp-file)] (fs/delete tmp-file) (is (thrown-with-msg? IllegalArgumentException #"^Unable to open 'ssl-cert-chain' file:" (construct-ssl-x509-cert-chain "./dev-resources/config/jetty/ssl/certs/localhost.pem" (.getAbsolutePath tmp-file)))))) (testing "ssl-cert with single cert loaded into list" (validate-cert-lists-equal "./dev-resources/config/jetty/ssl/certs/localhost.pem" "./dev-resources/config/jetty/ssl/certs/localhost.pem" nil)) (testing "ssl-cert with multiple certs loaded into list" (validate-cert-lists-equal "./dev-resources/config/jetty/ssl/certs/master-with-all-cas.pem" "./dev-resources/config/jetty/ssl/certs/master-with-all-cas.pem" nil)) (testing (str "ssl-cert with single cert and ssl-cert-chain with " "multiple certs loaded into list") (validate-cert-lists-equal "./dev-resources/config/jetty/ssl/certs/master-with-all-cas.pem" "./dev-resources/config/jetty/ssl/certs/master.pem" "./dev-resources/config/jetty/ssl/certs/ca-master-intermediate-and-root.pem")) (testing (str "for ssl-cert with multiple certs and ssl-cert-chain with " "with one cert, only the first cert from ssl-cert is " "loaded into list with cert from ssl-cert-chain") (validate-cert-lists-equal "./dev-resources/config/jetty/ssl/certs/master-with-root-ca.pem" "./dev-resources/config/jetty/ssl/certs/master-with-intermediate-ca.pem" "./dev-resources/config/jetty/ssl/certs/ca-root.pem"))) jetty_core_test.clj000066400000000000000000000741051527232126200401120ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-core-test (:import (org.eclipse.jetty.server.handler ContextHandler ContextHandlerCollection) (java.security KeyStore) (java.net SocketTimeoutException Socket) (java.io InputStreamReader BufferedReader PrintWriter) (org.eclipse.jetty.server Server ServerConnector) (com.puppetlabs.ssl_utils SSLUtils)) (:require [clojure.test :refer :all] [clojure.java.jmx :as jmx] [ring.util.response :as rr] [puppetlabs.http.client.sync :as http-sync] [puppetlabs.kitchensink.core :as ks] [puppetlabs.trapperkeeper.services.webserver.jetty-core :as jetty] [puppetlabs.trapperkeeper.testutils.webserver :refer [with-test-webserver with-test-webserver-and-config]] [puppetlabs.trapperkeeper.app :as tk-app] [puppetlabs.trapperkeeper.services.webserver.jetty-default-config-test :refer [get-server-thread-pool-queue]] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service add-ring-handler]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [schema.test :as schema-test] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (deftest handlers (testing "create-handlers should allow for handlers to be added" (let [webserver-context (jetty/initialize-context) handlers (:handlers webserver-context)] (jetty/add-ring-handler webserver-context (fn [req] {:status 200 :body "I am a handler"}) "/" true false) (is (= (count (.getHandlers handlers)) 1))))) (defn validate-gzip-encoding-when-gzip-requested [body port] ;; The client/get function asks for compression by default (let [resp (http-sync/get (format "http://localhost:%d/" port))] (is (= (slurp (resp :body)) body)) (is (= (get-in resp [:orig-content-encoding]) "gzip") (format "Expected gzipped response, got this response: %s" resp)))) (defn validate-gzip-encoding-when-gzip-requested-on-post-requests [body port] ;; The client/post function asks for compression by default (let [resp (http-sync/post (format "http://localhost:%d/" port))] (is (= (slurp (resp :body)) body)) (is (= (get-in resp [:orig-content-encoding]) "gzip") (format "Expected gzipped response, got this response: %s" resp)))) (defn validate-no-gzip-encoding-when-gzip-not-requested [body port] ;; The client/get function asks for compression by default (let [resp (http-sync/get (format "http://localhost:%d/" port) {:decompress-body false})] (is (= (slurp (resp :body)) body)) ;; We should not receive a content-encoding header in the ;; uncompressed case (is (nil? (get-in resp [:headers "content-encoding"])) (format "Expected uncompressed response, got this response: %s" resp)))) (defn validate-no-gzip-encoding-even-though-gzip-requested [body port] ;; The client/get function asks for compression by default (let [resp (http-sync/get (format "http://localhost:%d/" port))] (is (= (slurp (resp :body)) body)) ;; We should not receive a content-encoding header in the ;; uncompressed case (is (nil? (get-in resp [:headers "content-encoding"])) (format "Expected uncompressed response, got this response: %s" resp)))) (deftest compression (with-test-logging (testing "should return" ;; Jetty may not Gzip encode a response body if the size of the response ;; is less than 256 bytes, so returning a larger body to ensure that Gzip ;; encoding is used where desired for these tests (let [body (apply str (repeat 1000 "f")) app (fn [req] (-> body (rr/response) (rr/status 200) (rr/content-type "text/plain") (rr/charset "UTF-8")))] (with-test-webserver app port (testing "a gzipped response when request wants a compressed one and server not configured with a default for gzip-enable" (validate-gzip-encoding-when-gzip-requested body port)) (testing "a gzipped response when a post request asks for a compressed one and the server not configured with a default for gzip-enable" (validate-gzip-encoding-when-gzip-requested-on-post-requests body port)) (testing "an uncompressed response when request doesn't ask for a compressed one and server not configured with a default for gzip-enable" (validate-no-gzip-encoding-when-gzip-not-requested body port))) (with-test-webserver-and-config app port {:gzip-enable true} (testing "a gzipped response when request wants a compressed one and server configured with a true value for gzip-enable" (validate-gzip-encoding-when-gzip-requested body port)) (testing "an uncompressed response when request doesn't ask for a compressed one and server configured with a true value for gzip-enable" (validate-no-gzip-encoding-when-gzip-not-requested body port))) (with-test-webserver-and-config app port {:gzip-enable false} (testing "an uncompressed response when request wants a compressed one but server configured with a false value for gzip-enable" (validate-no-gzip-encoding-even-though-gzip-requested body port)) (testing "an uncompressed response when request doesn't ask for a compressed one and server configured with a false value for gzip-enable" (validate-no-gzip-encoding-when-gzip-not-requested body port))) (with-test-webserver-and-config app port {:gzip-enable true :access-log-config (str "./dev-resources/puppetlabs/trapperkeeper/services/webserver/" "request-logging.xml")} (testing "(TK-429) a gzipped response when request wants a compressed one and server configured with a true value for gzip-enable and an access-log-config" (validate-gzip-encoding-when-gzip-requested body port))))))) (deftest response-uses-chunked-encoding (with-test-logging (testing "responses use chunked transfer encoding instead of content-length" (let [body (apply str (repeat 1000 "f")) app (fn [req] (-> body (rr/response) (rr/status 200) (rr/content-type "text/plain") (rr/charset "UTF-8")))] (with-test-webserver app port (let [resp (http-sync/get (format "http://localhost:%d/" port) {:decompress-body false :as :text})] (is (= 200 (:status resp))) (is (= "chunked" (get-in resp [:headers "transfer-encoding"])) "response should use chunked encoding to avoid TLS 1.3 NewSessionTicket hang") (is (nil? (get-in resp [:headers "content-length"])) "response should not have content-length when using chunked encoding"))) (with-test-webserver-and-config app port {:gzip-enable true} (let [resp (http-sync/get (format "http://localhost:%d/" port))] (is (= 200 (:status resp))) (is (= body (slurp (:body resp)))) (is (= "gzip" (get-in resp [:orig-content-encoding])) "gzip should still work with chunked encoding"))) (testing "small responses also use chunked encoding" (let [small-app (fn [req] (-> "hello" (rr/response) (rr/status 200) (rr/content-type "text/plain")))] (with-test-webserver small-app port (let [resp (http-sync/get (format "http://localhost:%d/" port) {:decompress-body false :as :text})] (is (= 200 (:status resp))) (is (= "chunked" (get-in resp [:headers "transfer-encoding"]))) (is (nil? (get-in resp [:headers "content-length"]))) (is (= "hello" (:body resp))))))))))) (deftest jmx (with-test-logging (testing "by default Jetty JMX support is enabled" (with-test-webserver #() _ (testing "and should return a valid Jetty MBeans object" (let [mbeans (jmx/mbean-names "org.eclipse.jetty.jmx:*")] (is (not (empty? mbeans))))) (testing "and should not return data when we query for something unexpected" (let [mbeans (jmx/mbean-names "foobarbaz:*")] (is (empty? mbeans)))))) (testing "server starts up and shuts down cleanly when jmx is disabled" (let [config {:webserver {:port 9000 :host "localhost" :jmx-enable "false"}}] (with-app-with-config app [jetty-service] config))))) (deftest override-webserver-settings!-tests (let [default-state {:mbean-container nil :overrides-read-by-webserver false :overrides nil :endpoints {} :ssl-context-client-factory nil :ssl-context-server-factory nil} webserver-context (fn [state] {:handlers (ContextHandlerCollection. (into-array ContextHandler [])) :server nil :state (atom (merge default-state state))})] (testing "able to associate overrides when overrides not already set" (let [context (webserver-context {})] (is (= {:host "override-value-1" :ssl-host "override-value-2"} (jetty/override-webserver-settings! context {:host "override-value-1" :ssl-host "override-value-2"})) "Unexpected overrides returned from override-webserver-settings!") (is (= @(:state context) (merge default-state {:overrides {:host "override-value-1" :ssl-host "override-value-2"}})) "Unexpected config set for override-webserver-settings!"))) (testing "unable to associate overrides when overrides already processed by webserver but overrides were not present" (let [context (webserver-context {:overrides-read-by-webserver true})] (is (thrown-with-msg? java.lang.IllegalStateException #"overrides cannot be set because webserver has already processed the config" (jetty/override-webserver-settings! context {:host "override-value-1" :ssl-host "override-value-2"})) "Call to override-webserver-settings! did not fail as expected.") (is (= (merge default-state {:overrides-read-by-webserver true}) @(:state context)) "Config unexpectedly changed for override-webserver-settings!"))) (testing "unable to associate override when overrides already processed by webserver and overrides were previously set" (let [context (webserver-context {:overrides {:myoverride "my-override-value"} :overrides-read-by-webserver true})] (is (thrown-with-msg? java.lang.IllegalStateException #"overrides cannot be set because they have already been set and webserver has already processed the config" (jetty/override-webserver-settings! context {:host "override-value-1" :ssl-host "override-value-2"})) "Call to override-webserver-settings! did not fail as expected.") (is (= (merge default-state {:overrides {:myoverride "my-override-value"} :overrides-read-by-webserver true}) @(:state context)) "Config unexpectedly changed for override-webserver-settings!"))) (testing "unable to associate override when overrides were previously set" (let [context (webserver-context {:overrides {:myoverride "my-override-value"}})] (is (thrown-with-msg? java.lang.IllegalStateException #"overrides cannot be set because they have already been set" (jetty/override-webserver-settings! context {:host "override-value-1" :ssl-host "override-value-2"})) "Call to override-webserver-settings! did not fail as expected.") (is (= (merge default-state {:overrides {:myoverride "my-override-value"}}) @(:state context)) "config unexpectedly changed for override-webserver-settings!"))))) (defn munge-common-connector-config [config connector-keyword] (-> config (update-in [connector-keyword :port] (fnil identity 0)) (update-in [connector-keyword :host] (fnil identity "localhost")) (update-in [connector-keyword :request-header-max-size] identity) (update-in [connector-keyword :acceptor-threads] identity) (update-in [connector-keyword :selector-threads] identity) (update-in [connector-keyword :idle-timeout-milliseconds] identity))) (defn munge-http-connector-config [config] (-> config (update-in [:max-threads] identity) (update-in [:queue-max-size] identity) (update-in [:jmx-enable] ks/parse-bool) (munge-common-connector-config :http))) (defn get-keystore-instance [] (if (SSLUtils/isFIPS) (KeyStore/getInstance SSLUtils/BOUNCYCASTLE_FIPS_KEYSTORE) (-> (KeyStore/getDefaultType) (KeyStore/getInstance)))) (defn munge-http-and-https-connector-config [config] (-> config (munge-http-connector-config) (munge-common-connector-config :https) (update-in [:https :protocols] identity) (update-in [:https :cipher-suites] identity) (update-in [:https :client-auth] (fnil identity :none)) (update-in [:https :keystore-config] (fnil identity {:truststore (get-keystore-instance) :key-password "hello" :keystore (get-keystore-instance)})))) (defn create-server-with-config [config] (jetty/create-server (jetty/initialize-context) config)) (defn create-server-with-partial-http-config [config] (create-server-with-config (munge-http-connector-config config))) (defn create-server-with-partial-http-and-https-config [config] (create-server-with-config (munge-http-and-https-connector-config config))) (defn get-thread-pool-for-partial-http-config [config] (.getThreadPool (create-server-with-partial-http-config config))) (def get-thread-pool-for-default-server (.getThreadPool (Server.))) (def default-server-max-threads (.getMaxThreads get-thread-pool-for-default-server)) (defn get-max-threads-for-partial-http-config [config] (.getMaxThreads (get-thread-pool-for-partial-http-config config))) (deftest create-server-max-threads-test (testing "default max threads passed through to thread pool" (is (= default-server-max-threads (get-max-threads-for-partial-http-config {:max-threads nil})))) (testing "custom max threads passed through to thread pool" (is (= 9042 (get-max-threads-for-partial-http-config {:max-threads 9042, :queue-max-size nil}))))) (deftest create-server-queue-max-size-test (with-test-logging (let [get-queue-for-partial-http-config (fn [config] (get-server-thread-pool-queue (create-server-with-config (munge-http-connector-config config)))) default-server-min-threads (.getMinThreads get-thread-pool-for-default-server)] (testing "default queue max size passed through to thread pool queue" (is (= (.getMaxCapacity (get-server-thread-pool-queue (Server.))) (.getMaxCapacity (get-queue-for-partial-http-config {:queue-max-size nil}))))) (testing "custom default queue max size passed through to thread pool queue" (is (= 393 (.getMaxCapacity (get-queue-for-partial-http-config {:queue-max-size 393}))))) (testing (str "default max threads passed through to thread pool when " "queue-max-size set") (is (= default-server-max-threads (get-max-threads-for-partial-http-config {:max-threads nil, :queue-max-size 1})))) (testing "min threads passed through to thread pool when queue-max-size set" (is (= default-server-min-threads (.getMinThreads (get-thread-pool-for-partial-http-config {:queue-max-size 1}))))) (testing "idle timeout passed through to thread pool when queue-max-size set" (is (= (.getIdleTimeout get-thread-pool-for-default-server) (.getIdleTimeout (get-thread-pool-for-partial-http-config {:queue-max-size 1}))))) (testing (str "queue min size set on thread pool queue equal to min threads " "when queue max size greater than min threads") (is (= default-server-min-threads (.getCapacity (get-queue-for-partial-http-config {:queue-max-size (inc default-server-min-threads)}))))) (testing (str "queue min size set on thread pool queue equal to queue max " "size when queue max size less than min threads") (let [queue-max-size (dec default-server-min-threads)] (is (= queue-max-size (.getCapacity (get-queue-for-partial-http-config {:queue-max-size queue-max-size}))))))))) (deftest create-server-idle-timeout-test (with-test-logging (testing "idle-timeout configured properly for http connector" (let [server (create-server-with-partial-http-config {:http {:idle-timeout-milliseconds 3000}}) connectors (.getConnectors server)] (is (= 1 (count connectors)) "Unexpected number of connectors for server") (is (= 3000 (.getIdleTimeout (first connectors))) "Unexpected idle time for connector"))) (testing "idle-timeout configured properly for multiple connectors" (let [server (create-server-with-partial-http-and-https-config {:http {:port 25 :idle-timeout-milliseconds 9001} :https {:port 92 :idle-timeout-milliseconds 9002}}) connectors (.getConnectors server)] (is (= 2 (count connectors)) "Unexpected number of connectors for server") (is (= 25 (.getPort (first connectors))) "Unexpected port for first connector") (is (= 9001 (.getIdleTimeout (first connectors))) "Unexpected idle timeout for first connector") (is (= 92 (.getPort (second connectors))) "Unexpected port for second connector") (is (= 9002 (.getIdleTimeout (second connectors))) "Unexpected idle time for second connector"))))) (deftest create-server-acceptor-threads-test (with-test-logging (testing "nil acceptors configured properly for http connector" (let [server (create-server-with-partial-http-config {:http {:acceptor-threads nil}}) connectors (.getConnectors server)] (is (= 1 (count connectors)) "Unexpected number of connectors for server") (is (= (.getAcceptors (ServerConnector. (Server.))) (.getAcceptors (first connectors))) "Unexpected number of acceptor threads for connector"))) (testing "non-nil acceptors configured properly for http connector" (let [server (create-server-with-partial-http-config {:http {:acceptor-threads 42}}) connectors (.getConnectors server)] (is (= 1 (count connectors)) "Unexpected number of connectors for server") (is (= 42 (.getAcceptors (first connectors))) "Unexpected number of acceptor threads for connector"))) (testing "non-nil acceptors configured properly for multiple connectors" (let [server (create-server-with-partial-http-and-https-config {:http {:port 25 :acceptor-threads 91} :https {:port 92 :acceptor-threads 63}}) connectors (.getConnectors server)] (is (= 2 (count connectors)) "Unexpected number of connectors for server") (is (= 25 (.getPort (first connectors))) "Unexpected port for first connector") (is (= 91 (.getAcceptors (first connectors))) "Unexpected number of acceptor threads for first connector") (is (= 92 (.getPort (second connectors))) "Unexpected port for second connector") (is (= 63 (.getAcceptors (second connectors))) "Unexpected number of acceptor threads for second connector"))))) (deftest create-server-selector-threads-test (with-test-logging (letfn [(selector-threads [connector] (-> connector (.getSelectorManager) (.getSelectorCount)))] (testing "nil selectors configured properly for http connector" (let [server (create-server-with-partial-http-config {:http {:selector-threads nil}}) connectors (.getConnectors server)] (is (= 1 (count connectors)) "Unexpected number of connectors for server") (is (= (selector-threads (ServerConnector. (Server.))) (selector-threads (first connectors))) "Unexpected number of selectors for connector"))) (testing "non-nil selectors configured properly for http connector" (let [server (create-server-with-partial-http-config {:http {:selector-threads 42}}) connectors (.getConnectors server)] (is (= 1 (count connectors)) "Unexpected number of connectors for server") (is (= 42 (selector-threads (first connectors))) "Unexpected number of selector threads for connector"))) (testing "non-nil selectors configured properly for multiple connectors" (let [server (create-server-with-partial-http-and-https-config {:http {:port 25 :selector-threads 91} :https {:port 92 :selector-threads 63}}) connectors (.getConnectors server)] (is (= 2 (count connectors)) "Unexpected number of connectors for server") (is (= 25 (.getPort (first connectors))) "Unexpected port for first connector") (is (= 91 (selector-threads (first connectors))) "Unexpected number of selector threads for first connector") (is (= 92 (.getPort (second connectors))) "Unexpected port for second connector") (is (= 63 (selector-threads (second connectors))) "Unexpected number of selector threads for second connector")))))) (deftest test-idle-timeout (let [read-lines (fn [r] (let [sb (StringBuilder.)] (loop [l (.readLine r)] (when l (.append sb l) (.append sb "\n") ;; readLine will block until the socket is closed, ;; or will throw a SocketTimeoutException if there ;; is no data available within the SoTimeout value. (recur (.readLine r)))) (.toString sb))) body "Hi World\n" path "/hi_world" ring-handler (fn [req] {:status 200 :body body}) read-response (fn [client-so-timeout] (let [s (Socket. "localhost" 9000) out (PrintWriter. (.getOutputStream s) true)] (.setSoTimeout s client-so-timeout) (.println out (str "GET " path " HTTP/1.1\n" "Host: localhost\n" "\n")) (let [in (BufferedReader. (InputStreamReader. (.getInputStream s)))] (read-lines in))))] (let [config {:webserver {:port 9000 :host "localhost" :idle-timeout-milliseconds 500}}] (with-test-logging (with-app-with-config app [jetty-service] config (let [s (tk-app/get-service app :WebserverService) add-ring-handler (partial add-ring-handler s)] (add-ring-handler ring-handler path) (testing "Verify that server doesn't close socket before idle timeout" ;; if we set the client socket timeout lower than the server ;; socket timeout, we should get a timeout exception from the ;; client side while attempting to read from the socket. (is (thrown-with-msg? SocketTimeoutException #"Read timed out" (read-response 250)))) (testing "Verify that server closes the socket after idle timeout" ;; if we set the client socket timeout higher than the server, ;; then the server should close the socket after its timeout, ;; which will cause our read to stop blocking and allow us to ;; validate the contents of the data we read from the socket. (let [resp (read-response 750)] (is (re-find #"(?is)HTTP.*200 OK.*Hi World" resp)))))))))) (deftest request-body-max-size (with-test-logging (let [bigger-post-data (apply str (repeat 21 "f")) smaller-post-data (apply str (repeat 20 "f")) no-request-body-response "no request body" get-request (fn [port] (http-sync/get (format "http://localhost:%d/" port) {:as :text})) post-request (fn [port body] (http-sync/post (format "http://localhost:%d/" port) {:headers {"content-type" "text/plain"} :body body :as :text})) app (fn [req] (let [body (slurp (:body req))] (-> (if (empty? body) no-request-body-response body) (rr/response) (rr/status 200) (rr/content-type "text/plain") (rr/charset "UTF-8"))))] (with-test-webserver-and-config app port {:request-body-max-size 20} (testing "posting data larger than the configured limit fails with 413" (let [response (post-request port bigger-post-data)] (is (= 413 (:status response))) ;; In Jetty 12, 413 responses include an HTML error page body (is (re-find #"Payload Too Large" (:body response))))) (testing "posting data within the configured limit succeeds" (let [response (post-request port smaller-post-data)] (is (= 200 (:status response))) (is (= smaller-post-data (:body response))))) (testing "request with no content-length succeeds when limit configured" (let [response (get-request port)] (is (= 200 (:status response))) (is (= no-request-body-response (:body response))))) (testing "request with malformed content-length does not cause a 500" (let [sock (Socket. "localhost" port) writer (PrintWriter. (.getOutputStream sock) true) request-lines (str "POST / HTTP/1.1\r\n" "Host: localhost\r\n" "Content-Type: text/plain\r\n" "Content-Length: abc\r\n" "\r\n" "body")] (.setSoTimeout sock 5000) (.println writer request-lines) (let [reader (BufferedReader. (InputStreamReader. (.getInputStream sock))) status-line (.readLine reader)] (.close sock) (is (some? status-line) "Server should respond with a status line") ;; Jetty rejects malformed Content-Length at the parser level (400). ;; A 500 would indicate an unhandled exception in our handler. (is (re-find #"^HTTP/1\.1 400" status-line) "Malformed Content-Length should be rejected by the parser as 400")))))))) jetty_default_config_test.clj000066400000000000000000000212311527232126200421230ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-default-config-test " ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; VALIDATION OF DEFAULT JETTY CONFIGURATION VALUES ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; NOTE: IF A TEST IN THIS NAMESPACE FAILS, AND YOU ALTER THE VALUE TO MAKE IT PASS, IT IS YOUR RESPONSIBILITY TO DOUBLE-CHECK THE DOCS TO SEE IF THERE IS ANYWHERE IN THEM THAT THE NEW VALUE NEEDS TO BE ADDED. This namespace is a little different than most of our test namespaces. It's not really intended to test any of our own code, it's just here to provide us with a warning in the event that Jetty changes any of the default configuration values. In the conversation leading up to https://tickets.puppetlabs.com/browse/TK-168 we decided that it was generally not a good idea to be hard-coding our own default values for the settings that we exposed, and that it would be a better idea to allow Jetty to use its implicit default values for any settings that are not explicitly set in a TK config file. Otherwise, we're at risk of the Jetty authors coming up with a really compelling reason to change a default value between releases, and us not picking up that change. Therefore, we decided that all the settings we expose should just fall through to Jetty's implicit defaults, and that individual TK application authors can override any appropriate settings in their packaging if needed. However, there was some concern that if an upstream Jetty default were to change without us knowing about it, it could have other implications for our applications that we ought to be aware of. Therefore, we agreed that it would be best if we had some way of making sure we could identify when that situation arose. That is the purpose of this namespace. It basically provides assertions to validate that we know what Jetty's implicit default value is for all of the settings we expose. If we bump to a new version of Jetty in the future and any of these implicit defaults have changed, these tests will fail. If that happens, we can attempt to evaluate the impact of the change and react accordingly." (:require [clojure.test :refer :all] [schema.test :as schema-test] [puppetlabs.kitchensink.core :as ks] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer [jetty-service]] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.services :refer [service-context]] [puppetlabs.trapperkeeper.services.webserver.jetty-core :as core] [puppetlabs.trapperkeeper.testutils.webserver :as testutils] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]]) (:import (org.eclipse.jetty.server HttpConfiguration ServerConnector Server) (org.eclipse.jetty.util.thread QueuedThreadPool))) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (deftest default-request-header-max-size-test (let [http-config (HttpConfiguration.)] ;; See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-server/src/main/java/org/eclipse/jetty/server/HttpConfiguration.java#L55 (is (= 8192 (.getRequestHeaderSize http-config)) "Unexpected default for 'request-header-max-size'"))) (deftest default-proxy-http-client-settings-test (with-test-logging (with-app-with-config app [jetty-service] {:webserver {:host "localhost" :port 8080}} (let [s (get-service app :WebserverService) server-context (get-in (service-context s) [:jetty-servers :default]) proxy-servlet (core/proxy-servlet server-context {:host "localhost" :path "/foo" :port 8080} {}) _ (core/add-servlet-handler server-context proxy-servlet "/proxy" {} true false) client (.createHttpClient proxy-servlet)] ;; See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-client/src/main/java/org/eclipse/jetty/client/HttpClient.java#L135 (is (= 4096 (.getRequestBufferSize client)) "Unexpected default for proxy 'request-buffer-size'") ;; See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java#L304-L307 (is (= 30000 (.getIdleTimeout client)) "Unexpected default for proxy 'idle-timeout'") (.stop client))))) (defn selector-thread-count [max-threads] "The number of selector threads that should be allocated per connector. https://github.com/eclipse/jetty.project/blob/jetty-9.4.11.v20180605/jetty-io/src/main/java/org/eclipse/jetty/io/SelectorManager.java#L70-L74" (max 1 (min (int (/ max-threads 16)) (int (/ (ks/num-cpus) 2))))) (def acceptor-thread-count "The number of acceptor threads that should be allocated per connector. See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.11.v20180605/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java#L202" (max 1 (min 4 (int (/ (ks/num-cpus) 8))))) (defn reserved-thread-count "Jetty will reserve threads for future connector work on start. See https://github.com/eclipse/jetty.project/blob/jetty-9.4.11.v20180605/jetty-util/src/main/java/org/eclipse/jetty/util/thread/ReservedThreadExecutor.java#L104" [max-threads] (max 1 (min (ks/num-cpus) (int (/ max-threads 10))))) (deftest default-connector-settings-test (let [connector (ServerConnector. (Server.))] ;; See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-server/src/main/java/org/eclipse/jetty/server/AbstractConnector.java#L150 (is (= 30000 (.getIdleTimeout connector)) "Unexpected default for 'idle-timeout-milliseconds'") (is (= acceptor-thread-count (.getAcceptors connector)) "Unexpected default for 'acceptor-threads' and 'ssl-acceptor-threads'") (is (= (selector-thread-count (-> connector .getExecutor .getMaxThreads)) (.getSelectorCount (.getSelectorManager connector))) "Unexpected default for 'selector-threads' and 'ssl-selector-threads'"))) (defn get-max-threads-for-server [server] (.getMaxThreads (.getThreadPool server))) (defn get-server-thread-pool-queue [server] (let [thread-pool (.getThreadPool server) ;; Using reflection here because the .getQueue method is protected and I ;; didn't see any other way to pull the queue back from the thread pool. get-queue-method (-> thread-pool (.getClass) (.getDeclaredMethod "getQueue" nil)) _ (.setAccessible get-queue-method true)] (.invoke get-queue-method thread-pool nil))) (deftest default-server-settings-test (let [server (Server.)] ;; See: https://github.com/eclipse/jetty.project/blob/jetty-10.0.15/jetty-server/src/main/java/org/eclipse/jetty/server/Server.java#L183-L186 (is (= 0 (.getStopTimeout server)) "Unexpected default for 'shutdown-timeout-seconds'") ;; See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-util/src/main/java/org/eclipse/jetty/util/thread/QueuedThreadPool.java#L71 (is (= 200 (get-max-threads-for-server server)) "Unexpected default for 'max-threads'") ;; See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-util/src/main/java/org/eclipse/jetty/util/BlockingArrayQueue.java#L92 (is (= (Integer/MAX_VALUE) (.getMaxCapacity (get-server-thread-pool-queue server))) "Unexpected default for 'queue-max-size'"))) (defn required-threads-for-sized-threadpool-per-connector [threadpool-size] "The total number of threads needed per attached connector. This scales with the threadpool size and acceptor threads are not allocated until after reserved and selector threads have be allocated. For an overview see: https://support.sonatype.com/hc/en-us/articles/360000744687-Understanding-Eclipse-Jetty-9-4-8-Thread-Allocation This is unused below so we can configure the needed threads in a trivial case without referencing the max threads. Left for documentation." (+ (reserved-thread-count threadpool-size) (selector-thread-count threadpool-size) acceptor-thread-count)) jetty_service_handlers_test.clj000066400000000000000000000617321527232126200425040ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-service-handlers-test (:require [clojure.test :refer :all] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer :all] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [puppetlabs.trapperkeeper.testutils.webserver :as testutils] [puppetlabs.trapperkeeper.testutils.webserver.common :refer :all] [schema.test :as schema-test]) (:import (java.nio.file Files Paths) (java.nio.file.attribute FileAttribute) (jakarta.servlet ServletContextListener) (jakarta.servlet.http HttpServlet HttpServletRequest HttpServletResponse) (servlet SimpleServlet))) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (deftest static-content-test (with-test-logging (testing "static content context" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-context-handler (partial add-context-handler s) path "/resources" resource "logback.xml"] (add-context-handler dev-resources-dir path) (let [response (http-get (str "http://localhost:8080" path "/" resource))] (is (= (:status response) 200)) (is (= (:body response) (slurp (str dev-resources-dir resource)))))))) (testing "static content context with add-context-handler-to" (with-app-with-config app [jetty-service] jetty-multiserver-plaintext-config (let [s (get-service app :WebserverService) add-context-handler (partial add-context-handler s) path "/resources" resource "logback.xml"] (add-context-handler dev-resources-dir path {:server-id :foo}) (let [response (http-get (str "http://localhost:8085" path "/" resource))] (is (= (:status response) 200)) (is (= (:body response) (slurp (str dev-resources-dir resource)))))))) (testing "customization of static content context" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-context-handler (partial add-context-handler s) path "/resources" body "Hey there" servlet-path "/hey" servlet (SimpleServlet. body "text/html" false) context-listeners [(reify ServletContextListener (contextInitialized [this event] (doto (.addServlet (.getServletContext event) "simple" servlet) (.addMapping (into-array [servlet-path])))) (contextDestroyed [this event]))]] (add-context-handler dev-resources-dir path {:context-listeners context-listeners}) (let [response (http-get (str "http://localhost:8080" path servlet-path))] (is (= (:status response) 200)) (is (= "text/html;charset=utf-8" (get-in response [:headers "content-type"]))) (is (= (:body response) body)))))))) (deftest add-context-handler-symlinks-test (with-test-logging (let [resource "logback.xml" resource-link "logback-link.xml" logback (slurp (str dev-resources-dir resource)) link (Paths/get (str dev-resources-dir resource-link) (into-array java.lang.String [])) file (Paths/get resource (into-array java.lang.String []))] (try (Files/createSymbolicLink link file (into-array FileAttribute [])) (testing "symlinks served when :follow-links is true" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-context-handler (partial add-context-handler s) path "/resources"] (add-context-handler dev-resources-dir path {:follow-links true}) (let [response (http-get (str "http://localhost:8080" path "/" resource))] (is (= (:status response) 200)) (is (= (:body response) logback))) (let [response (http-get (str "http://localhost:8080" path "/" resource-link))] (is (= (:status response) 200)) (is (= (:body response) logback)))))) (testing "symlinks not served when :follow-links is false" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-context-handler (partial add-context-handler s) path "/resources"] (add-context-handler dev-resources-dir path {:follow-links false}) (let [response (http-get (str "http://localhost:8080" path "/" resource))] (is (= (:status response) 200)) (is (= (:body response) logback))) (let [response (http-get (str "http://localhost:8080" path "/" resource-link))] (is (= (:status response) 404)))))) (finally (Files/delete link)))))) (deftest servlet-test (with-test-logging (testing "request to servlet over http succeeds" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-servlet-handler (partial add-servlet-handler s) body "Hey there" path "/hey" servlet (SimpleServlet. body "text/html" false)] (add-servlet-handler servlet path) (let [response (http-get (str "http://localhost:8080" path))] (is (= (:status response) 200)) (is (= "text/html;charset=utf-8" (get-in response [:headers "content-type"]))) (is (= (:body response) body)))))) (testing "request to servlet with json content over http succeeds" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-servlet-handler (partial add-servlet-handler s) body "{}" path "/hey" servlet (SimpleServlet. body "application/json;charset=utf-8" true)] (add-servlet-handler servlet path) (let [response (http-get (str "http://localhost:8080" path))] (is (= (:status response) 200)) (is (= "application/json;charset=utf-8" (get-in response [:headers "content-type"]))) (is (= (:body response) body)))))) (testing "request to servlet over http succeeds with add-servlet-handler-to" (with-app-with-config app [jetty-service] jetty-multiserver-plaintext-config (let [s (get-service app :WebserverService) add-servlet-handler (partial add-servlet-handler s) body "Hey there" path "/hey" servlet (SimpleServlet. body "text/html" false)] (add-servlet-handler servlet path {:server-id :foo}) (let [response (http-get (str "http://localhost:8085" path))] (is (= (:status response) 200)) (is (= "text/html;charset=utf-8" (get-in response [:headers "content-type"]))) (is (= (:body response) body)))))) (testing "request to servlet initialized with empty param succeeds" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-servlet-handler (partial add-servlet-handler s) body "Hey there" path "/hey" servlet (SimpleServlet. body "text/html" false)] (add-servlet-handler servlet path {:servlet-init-params {}}) (let [response (http-get (str "http://localhost:8080" path))] (is (= (:status response) 200)) (is (= "text/html;charset=utf-8" (get-in response [:headers "content-type"]))) (is (= (:body response) body)))))) (testing "request to servlet initialized with non-empty params succeeds" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-servlet-handler (partial add-servlet-handler s) body "Hey there" path "/hey" init-param-one "value of init param one" init-param-two "value of init param two" servlet (SimpleServlet. body "text/html" false)] (add-servlet-handler servlet path {:servlet-init-params {"init-param-one" init-param-one "init-param-two" init-param-two}}) (let [response (http-get (str "http://localhost:8080" path "/init-param-one"))] (is (= (:status response) 200)) (is (= "text/html;charset=utf-8" (get-in response [:headers "content-type"]))) (is (= (:body response) init-param-one))) (let [response (http-get (str "http://localhost:8080" path "/init-param-two"))] (is (= (:status response) 200)) (is (= "text/html;charset=utf-8" (get-in response [:headers "content-type"]))) (is (= (:body response) init-param-two)))))))) (deftest war-test (with-test-logging (testing "WAR support" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-war-handler (partial add-war-handler s) path "/test" war "helloWorld.war"] (add-war-handler (str dev-resources-dir war) path) (let [response (http-get (str "http://localhost:8080" path "/hello"))] (is (= (:status response) 200)) (is (= (:body response) "\nHello World Servlet\nHello World!!\n\n")))))) (testing "WAR support with add-war-handler-to" (with-app-with-config app [jetty-service] jetty-multiserver-plaintext-config (let [s (get-service app :WebserverService) add-war-handler (partial add-war-handler s) path "/test" war "helloWorld.war"] (add-war-handler (str dev-resources-dir war) path {:server-id :foo}) (let [response (http-get (str "http://localhost:8085" path "/hello"))] (is (= (:status response) 200)) (is (= (:body response) "\nHello World Servlet\nHello World!!\n\n")))))))) (deftest endpoints-test (testing "Retrieve all endpoints" (with-test-logging (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) path-context "/ernie" path-context2 "/gonzo" path-context3 "/goblinking" path-ring "/bert" path-servlet "/foo" path-war "/bar" path-proxy "/baz" get-registered-endpoints (partial get-registered-endpoints s) add-context-handler (partial add-context-handler s) add-ring-handler (partial add-ring-handler s) add-servlet-handler (partial add-servlet-handler s) add-war-handler (partial add-war-handler s) add-proxy-route (partial add-proxy-route s) ring-handler (fn [req] {:status 200 :body "Hi world"}) body "This is a test" servlet (SimpleServlet. body "text/html" false) context-listeners [(reify ServletContextListener (contextInitialized [this event] (doto (.addServlet (.getServletContext event) "simple" servlet) (.addMapping (into-array [path-servlet])))) (contextDestroyed [this event]))] war "helloWorld.war" target {:host "0.0.0.0" :port 9000 :path "/ernie"} target2 {:host "localhost" :port 10000 :path "/kermit"}] (add-context-handler dev-resources-dir path-context) (add-context-handler dev-resources-dir path-context2 {:context-listeners []}) (add-context-handler dev-resources-dir path-context3 {:context-listeners context-listeners}) (add-ring-handler ring-handler path-ring) (add-servlet-handler servlet path-servlet) (add-war-handler (str dev-resources-dir war) path-war) (add-proxy-route target path-proxy) (add-proxy-route target2 path-proxy {}) (let [endpoints (get-registered-endpoints)] (is (= endpoints {"/ernie" [{:type :context :base-path dev-resources-dir :context-listeners []}] "/gonzo" [{:type :context :base-path dev-resources-dir :context-listeners []}] "/goblinking" [{:type :context :base-path dev-resources-dir :context-listeners context-listeners}] "/bert" [{:type :ring}] "/foo" [{:type :servlet :servlet (type servlet)}] "/bar" [{:type :war :war-path (str dev-resources-dir war)}] "/baz" [{:type :proxy :target-host "0.0.0.0" :target-port 9000 :target-path "/ernie"} {:type :proxy :target-host "localhost" :target-port 10000 :target-path "/kermit"}]}))))))) (testing "Log endpoints" (with-test-logging (with-app-with-config app [jetty-service] jetty-multiserver-plaintext-config (let [s (get-service app :WebserverService) log-registered-endpoints (partial log-registered-endpoints s) add-ring-handler (partial add-ring-handler s) ring-handler (fn [req] {:status 200 :body "Hi world"}) path-ring "/bert"] (add-ring-handler ring-handler path-ring) (log-registered-endpoints) (is (logged? #"^\{\"\/bert\" \[\{:type :ring\}\]\}$")) (is (logged? #"^\{\"\/bert\" \[\{:type :ring\}\]\}$" :info))))))) (deftest trailing-slash-redirect-test (with-test-logging (testing "redirects when no trailing slash is present are disabled by default" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) ring-handler (fn [req] {:status 200 :body "Hi world"}) path "/hello"] (add-ring-handler ring-handler path) (let [response (http-get "http://localhost:8080/hello" {:as :text :follow-redirects false})] (is (= (:status response) 200)) (is (= (:body response) "Hi world")) (is (= (get-in response [:opts :url]) "http://localhost:8080/hello")))))) (testing "redirects when no trailing slash is present and option is enabled" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) ring-handler (fn [req] {:status 200 :body "Hi world"}) path "/hello"] (add-ring-handler ring-handler path {:redirect-if-no-trailing-slash true}) (let [response (http-get "http://localhost:8080/hello" {:as :text :follow-redirects false})] ;; Jetty 12 uses 301 Moved Permanently with relative URL for trailing slash redirects (is (= (:status response) 301)) (is (= (get-in response [:headers "location"]) "/hello/")) (is (= (get-in response [:opts :url]) "http://localhost:8080/hello")))))))) (defn ring-handler-echoing-request-uri [] (fn [req] {:status 200 :body (:uri req)})) (deftest normalize-request-uri-enabled-for-ring-handler-test (with-test-logging (testing "when uri request normalization enabled for ring handler" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [webserver-service (get-service app :WebserverService)] (add-ring-handler webserver-service (ring-handler-echoing-request-uri) "/hello" {:normalize-request-uri true}) ;; Note: In Jetty 12, %2f (encoded slash) is not decoded for context ;; path matching. Use literal slashes where path separators are needed, ;; and test encoded characters within path segments. (testing "uri with encoded characters in path segment is properly decoded" (let [response (http-get "http://localhost:8080/hello/%77o%72l%64" {:as :text})] (is (= (:status response) 200)) (is (= (:body response) "/hello/world")))) (testing "uri with redundant slashes is normalized" (let [response (http-get "http://localhost:8080/hello//world" {:as :text})] (is (= (:status response) 200)) (is (= (:body response) "/hello/world")))) (testing "uri with relative path above root is rejected" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/%2E%2E/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 400)))) (testing "uri with relative path below root is rejected" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 400))))))))) (deftest normalize-request-uri-disabled-for-ring-handler-test (with-test-logging (testing "when uri request normalization disabled for ring handler" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [webserver-service (get-service app :WebserverService)] (add-ring-handler webserver-service (ring-handler-echoing-request-uri) "/hello" {:normalize-request-uri false}) ;; Note: In Jetty 12, %2f (encoded slash) is not decoded for context ;; path matching. Use literal slashes where path separators are needed. ;; When normalize-request-uri is false, the raw request URI is preserved. (testing "uri with encoded characters in path segment is NOT decoded" (let [response (http-get "http://localhost:8080/hello/%77o%72l%64" {:as :text})] (is (= (:status response) 200)) ;; Without normalization, encoded chars are preserved in request URI (is (= (:body response) "/hello/%77o%72l%64")))) (testing "uri with relative path above root is rejected" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/%2E%2E/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 400)))) (testing "uri with relative path below root is preserved" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/cleveland" {:as :text})] ;; Without normalization, .. segments are preserved in request URI (is (= (:body response) "/hello/world/%2E%2E/cleveland"))))))))) (defn servlet-echoing-request-uri [] (proxy [HttpServlet] [] (doGet [^HttpServletRequest request ^HttpServletResponse response] (-> response (.getWriter) (.print (.getRequestURI request))) (.setStatus response 200)))) (deftest normalize-request-uri-enabled-for-servlet-test (with-test-logging (testing "when uri request normalization enabled for servlet" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [webserver-service (get-service app :WebserverService)] (add-servlet-handler webserver-service (servlet-echoing-request-uri) "/hello" {:normalize-request-uri true}) ;; Note: In Jetty 12, %2f (encoded slash) is not decoded for context ;; path matching. Use literal slashes where path separators are needed. (testing "uri with encoded characters in path segment is properly decoded" (let [response (http-get "http://localhost:8080/hello/%77o%72l%64" {:as :text})] (is (= (:status response) 200)) (is (= (:body response) "/hello/world")))) (testing "uri with redundant slashes is normalized" (let [response (http-get "http://localhost:8080/hello//world" {:as :text})] (is (= (:status response) 200)) (is (= (:body response) "/hello/world")))) (testing "uri with relative path above root is rejected" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/%2E%2E/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 400)))) (testing "uri with relative path below root is rejected" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 400))))))))) (deftest normalize-request-uri-disabled-for-servlet-test (with-test-logging (testing "when uri request normalization disabled for servlet" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [webserver-service (get-service app :WebserverService)] (add-servlet-handler webserver-service (servlet-echoing-request-uri) "/hello" {:normalize-request-uri false}) ;; Note: In Jetty 12, %2f (encoded slash) is not decoded for context ;; path matching. Use literal slashes where path separators are needed. ;; When normalize-request-uri is false, the raw request URI is preserved. (testing "uri with encoded characters in path segment is NOT decoded" (let [response (http-get "http://localhost:8080/hello/%77o%72l%64" {:as :text})] (is (= (:status response) 200)) ;; Without normalization, encoded chars are preserved in request URI (is (= (:body response) "/hello/%77o%72l%64")))) (testing "uri with relative path above root is rejected" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/%2E%2E/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 400)))) (testing "uri with relative path below root is preserved" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 200)) ;; Without normalization, .. segments are preserved in request URI (is (= (:body response) "/hello/world/%2E%2E/cleveland"))))))))) jetty_service_override_settings_test.clj000066400000000000000000000304641527232126200444410ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-service-override-settings-test (:require [clojure.test :refer :all] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.services :as tk-services] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer :all] [puppetlabs.trapperkeeper.testutils.webserver.common :refer :all] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [schema.test :as schema-test] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (def dev-resources-config-dir (str dev-resources-dir "config/jetty/")) (def jetty-ssl-no-certs-config {:webserver {:ssl-host "0.0.0.0" :ssl-port 9001}}) (def jetty-plaintext-multiserver-override-config {:webserver {:bar {:port 8080 :default-server true} :foo {:port 9000}}}) (deftest test-override-webserver-settings! (let [ssl-port 9001 overrides {:ssl-port ssl-port :ssl-host "0.0.0.0" :ssl-cert (str dev-resources-config-dir "ssl/certs/localhost.pem") :ssl-cert-chain (str dev-resources-config-dir "ssl/certs/ca.pem") :ssl-key (str dev-resources-config-dir "ssl/private_keys/localhost.pem") :ssl-ca-cert (str dev-resources-config-dir "ssl/certs/ca.pem") :ssl-crl-path (str dev-resources-config-dir "ssl/crls/crls_none_revoked.pem")}] (testing "config override of all SSL settings before webserver starts is successful" (let [override-result (atom nil) service1 (tk-services/service [[:WebserverService override-webserver-settings!]] (init [this context] (reset! override-result (override-webserver-settings! overrides)) context))] (with-test-logging (with-app-with-config app [jetty-service service1] jetty-plaintext-multiserver-override-config (let [s (get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) body "Hi World" path "/hi_world" ring-handler (fn [req] {:status 200 :body body})] (add-ring-handler ring-handler path) (let [response (http-get (format "https://localhost:%d%s/" ssl-port path) default-options-for-https-client)] (is (= (:status response) 200) "Unsuccessful http response code ring handler response.") (is (= (:body response) body) "Unexpected body in ring handler response.")))) (is (logged? #"^webserver config overridden for key 'ssl-port'") "Didn't find log message for override of 'ssl-port'") (is (logged? #"^webserver config overridden for key 'ssl-host'") "Didn't find log message for override of 'ssl-host'") (is (logged? #"^webserver config overridden for key 'ssl-cert'") "Didn't find log message for override of 'ssl-cert'") (is (logged? #"^webserver config overridden for key 'ssl-cert-chain'") "Didn't find log message for override of 'ssl-cert-chain'") (is (logged? #"^webserver config overridden for key 'ssl-key'") "Didn't find log message for override of 'ssl-key'") (is (logged? #"^webserver config overridden for key 'ssl-ca-cert'") "Didn't find log message for override of 'ssl-ca-cert'") (is (logged? #"^webserver config overridden for key 'ssl-crl-path'") "Didn't find log message for override of 'ssl-crl-path'")) (is (= overrides @override-result) "Unexpected response to override-webserver-settings! call."))) (testing "config override of all SSL settings before webserver starts is successful when specifying a specific server" (let [override-result (atom nil) service1 (tk-services/service [[:WebserverService override-webserver-settings!]] (init [this context] (reset! override-result (override-webserver-settings! :foo overrides)) context))] (with-test-logging (with-app-with-config app [jetty-service service1] jetty-multiserver-plaintext-config (let [s (get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) body "Hi World" path "/hi_world" ring-handler (fn [req] {:status 200 :body body})] (add-ring-handler ring-handler path {:server-id :foo}) (let [response (http-get (format "https://localhost:%d%s/" ssl-port path) default-options-for-https-client)] (is (= (:status response) 200) "Unsuccessful http response code ring handler response.") (is (= (:body response) body) "Unexpected body in ring handler response.")))) (is (logged? #"^webserver config overridden for key 'ssl-port'") "Didn't find log message for override of 'ssl-port'") (is (logged? #"^webserver config overridden for key 'ssl-host'") "Didn't find log message for override of 'ssl-host'") (is (logged? #"^webserver config overridden for key 'ssl-cert'") "Didn't find log message for override of 'ssl-cert'") (is (logged? #"^webserver config overridden for key 'ssl-key'") "Didn't find log message for override of 'ssl-key'") (is (logged? #"^webserver config overridden for key 'ssl-ca-cert'") "Didn't find log message for override of 'ssl-ca-cert'") (is (logged? #"^webserver config overridden for key 'ssl-crl-path'") "Didn't find log message for override of 'ssl-crl-path'")) (is (= overrides @override-result) "Unexpected response to override-webserver-settings! call."))) (testing "SSL certificate settings can be overridden while other settings from the config are still honored -- ssl-port and ssl-host" (let [override-result (atom nil) overrides {:ssl-cert (str dev-resources-config-dir "ssl/certs/localhost.pem") :ssl-key (str dev-resources-config-dir "ssl/private_keys/localhost.pem") :ssl-ca-cert (str dev-resources-config-dir "ssl/certs/ca.pem")} service1 (tk-services/service [[:WebserverService override-webserver-settings!]] (init [this context] (reset! override-result (override-webserver-settings! overrides)) context))] (with-test-logging (with-app-with-config app [jetty-service service1] jetty-ssl-no-certs-config (let [s (get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) body "Hi World" path "/hi_world" ring-handler (fn [req] {:status 200 :body body})] (add-ring-handler ring-handler path) (let [response (http-get (format "https://localhost:%d%s/" ssl-port path) default-options-for-https-client)] (is (= (:status response) 200) "Unsuccessful http response code ring handler response.") (is (= (:body response) body) "Unexpected body in ring handler response.")))) (is (= overrides @override-result) "Unexpected response to override-webserver-settings! call.")))) (testing "attempt to override SSL settings fails when override call made after webserver has already started" (let [override-result (atom nil) service1 (tk-services/service [])] (with-test-logging (with-app-with-config app [jetty-service service1] jetty-plaintext-config (let [s (get-service app :WebserverService) override-webserver-settings! (partial override-webserver-settings! s)] (is (thrown-with-msg? java.lang.IllegalStateException #"overrides cannot be set because webserver has already processed the config" (override-webserver-settings! overrides)))))))) (testing "second attempt to override SSL settings fails" (let [second-override-result (atom nil) service1 (tk-services/service [[:WebserverService override-webserver-settings!]] (init [this context] (override-webserver-settings! overrides) (reset! second-override-result (is (thrown-with-msg? IllegalStateException #"overrides cannot be set because they have already been set" (override-webserver-settings! overrides)))) context))] (with-test-logging (with-app-with-config app [jetty-service service1] jetty-plaintext-config (let [s (get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) body "Hi World" path "/hi_world" ring-handler (fn [req] {:status 200 :body body})] (add-ring-handler ring-handler path) (let [response (http-get (format "https://localhost:%d%s/" ssl-port path) default-options-for-https-client)] (is (= (:status response) 200) "Unsuccessful http response code ring handler response.") (is (= (:body response) body) "Unexpected body in ring handler response.")))) (is (instance? IllegalStateException @second-override-result) "Second call to setting overrides did not throw expected exception.")))))) jetty_service_proxy_test.clj000066400000000000000000001054101527232126200420550ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-service-proxy-test (:import [java.net URI] [java.util.function Consumer]) (:require [clojure.test :refer :all] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer :all] [puppetlabs.trapperkeeper.testutils.webserver.common :refer :all] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.services :refer [service]] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [ring.middleware.params :as ring-params] [schema.test :as schema-test] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (defn query-params-handler [req] {:status 200 :body (str (:query-params req))}) (def app-wrapped (ring-params/wrap-params query-params-handler)) (defn proxy-ring-handler [req] (condp = (:uri req) "/hello/world" {:status 200 :body (str "Hello, World!" ((:headers req) "x-fancy-proxy-header") ((:headers req) "cookie"))} "/hello/earth" {:status 200 :body (str "Hello, Earth!" ((:headers req) "x-fancy-proxy-header") ((:headers req) "cookie"))} {:status 404 :body "D'oh"})) (defn redirect-test-handler [req] (condp = (:uri req) "/hello/world" {:status 200 :body "Hello, World!"} ;; Handle both with and without trailing slash for Jetty 12 compatibility "/hello/" {:status 302 :headers {"Location" "/hello/world"} :body ""} "/hello" {:status 302 :headers {"Location" "/hello/world"} :body ""} {:status 404 :body "D'oh"})) (defn redirect-wrong-host [req] {:status 302 :headers {"Location" "http://fakehost:5/hello"} :body ""}) (defn redirect-same-host [req] (condp = (:uri req) "/hello/world" {:status 200 :body "Hello, World!"} ;; Handle both with and without trailing slash for Jetty 12 compatibility "/hello/" {:status 302 :headers {"Location" "http://localhost:9000/hello/world"} :body ""} "/hello" {:status 302 :headers {"Location" "http://localhost:9000/hello/world"} :body ""} {:status 404 :body "D'oh"})) (defn redirect-different-proxy-path [req] (condp = (:uri req) "/goodbye/world" {:status 200 :body "Hello, World!"} ;; Handle both with and without trailing slash for Jetty 12 compatibility "/hello/" {:status 302 :headers {"Location" "http://localhost:9000/goodbye/world"} :body ""} "/hello" {:status 302 :headers {"Location" "http://localhost:9000/goodbye/world"} :body ""} {:status 404 :body "D'oh"})) (defn ring-handler-with-sleep "Makes a ring handler which sleeps for a set amount of milliseconds before responding. This is used to test timeout settings." [sleep-time] (fn [_] (Thread/sleep sleep-time) {:status 200 :body "This should have timed out."})) (defprotocol TkProxyService) (defn proxy-service [proxy-config proxy-opts proxy-path] (service TkProxyService [[:WebserverService add-proxy-route]] (init [this context] (if proxy-opts (add-proxy-route proxy-config proxy-path proxy-opts) (add-proxy-route proxy-config proxy-path)) context))) (defmacro with-target-and-proxy-servers [{:keys [target proxy proxy-config proxy-opts ring-handler register-proxy-route-before-server-start?]} & body] (let [proxy-path "/hello-proxy"] `(with-test-logging (with-app-with-config proxy-target-app# [jetty-service] {:webserver ~target} (let [target-webserver# (get-service proxy-target-app# :WebserverService)] (add-ring-handler target-webserver# ~ring-handler "/hello") (add-ring-handler target-webserver# ~ring-handler "/goodbye")) (if ~register-proxy-route-before-server-start? (let [proxy-service# (proxy-service ~proxy-config ~proxy-opts ~proxy-path)] (with-app-with-config proxy-app# [jetty-service proxy-service#] {:webserver ~proxy} ~@body)) (with-app-with-config proxy-app# [jetty-service] {:webserver ~proxy} (let [proxy-webserver# (get-service proxy-app# :WebserverService)] (if ~proxy-opts (add-proxy-route proxy-webserver# ~proxy-config ~proxy-path ~proxy-opts) (add-proxy-route proxy-webserver# ~proxy-config ~proxy-path))) ~@body)))))) (def common-ssl-config {:ssl-cert "./dev-resources/config/jetty/ssl/certs/localhost.pem" :ssl-key "./dev-resources/config/jetty/ssl/private_keys/localhost.pem" :ssl-ca-cert "./dev-resources/config/jetty/ssl/certs/ca.pem"}) (defn rewrite-uri-callback-fn [target-uri req] (URI. (.getScheme target-uri) nil (.getHost target-uri) (.getPort target-uri) "/hello/earth" nil nil)) (defn callback-fn "Callback function that adds a custom header to the proxy request. In Jetty 12, headers are modified via the headers() method which takes a Consumer." [proxy-req req] (.headers proxy-req (reify Consumer (accept [_ headers] (.put headers "x-fancy-proxy-header" "!!!"))))) (deftest test-basic-proxy-support (testing "basic proxy support when proxy handler registered after server start" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "basic proxy support when proxy handler registered before server start" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :ring-handler proxy-ring-handler :register-proxy-route-before-server-start? true} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "basic proxy support with add-proxy-route-to" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:foo {:host "0.0.0.0" :port 10000} :bar {:host "0.0.0.0" :port 8085 :default-server true}} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:server-id :foo} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!")))))) (deftest proxy-large-cookie (testing "proxy does not explode on a large cookie when properly configured" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000 :request-header-max-size 16192} :proxy {:host "0.0.0.0" :port 10000 :request-header-max-size 16192} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:request-buffer-size 16192} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world" {:headers {"Cookie" absurdly-large-cookie} :as :text})] (is (= (:status response) 200)) (is (= (:body response) (str "Hello, World!" absurdly-large-cookie))))))) (deftest proxy-with-orig-scheme (testing "basic proxy support with explicit :orig scheme" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:scheme :orig} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "basic proxy support with explicit \"orig\" scheme as string" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:scheme "orig"} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!")))))) (deftest basic-https-proxy (testing "basic https proxy support (pass-through https config)" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9001}) :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "basic https proxy support (pass-through https config) with explicit :orig scheme" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9001}) :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :proxy-opts {:scheme :orig} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "basic https proxy support (pass-through https config via explicit :use-server-config)" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9001}) :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :proxy-opts {:ssl-config :use-server-config} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!")))))) (deftest http-https-proxy-support (testing "http->https proxy support with explicit ssl config for proxy" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9000}) :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:scheme :https :ssl-config common-ssl-config} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "http->https proxy support with scheme as string value" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9000}) :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:scheme "https" :ssl-config common-ssl-config} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!")))))) (deftest https-http-proxy-support (testing "https->http proxy support" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9001} :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :proxy-opts {:scheme :http} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9001/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "https->http proxy support with scheme as string" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9001} :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :proxy-opts {:scheme "http"} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9001/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!")))))) (deftest proxy-support-with-callback (testing "basic http proxy support with callback function" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:callback-fn callback-fn} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!!!!"))))) (testing "basic https proxy support (pass-through https config) with callback function" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9001}) :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :proxy-opts {:callback-fn callback-fn} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!!!!"))))) (testing "http->https proxy support with explicit ssl config and callback function for proxy" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9000}) :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:scheme :https :ssl-config common-ssl-config :callback-fn callback-fn} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!!!!")))))) (deftest proxy-with-rewrite-uri-callback (testing "basic http proxy support with rewrite uri callback function" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:rewrite-uri-callback-fn rewrite-uri-callback-fn} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, Earth!"))))) (testing "basic https proxy support (pass-through https config) with rewrite uri callback function" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9001}) :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :proxy-opts {:rewrite-uri-callback-fn rewrite-uri-callback-fn} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9001/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "https://localhost:10001/hello-proxy/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, Earth!"))))) (testing "http->https proxy support with explicit ssl config and rewrite uri callback function for proxy" (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9000}) :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:scheme :https :ssl-config common-ssl-config :rewrite-uri-callback-fn rewrite-uri-callback-fn} :ring-handler proxy-ring-handler} (let [response (http-get "https://localhost:9000/hello/world" default-options-for-https-client)] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, Earth!")))))) (deftest proxy-with-query-params (testing "basic proxy support with query parameters" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :ring-handler app-wrapped} (let [response (http-get "http://localhost:9000/hello?foo=bar")] (is (= (:status response) 200)) (is (= (:body response) (str {"foo" "bar"})))) (let [response (http-get "http://localhost:10000/hello-proxy?foo=bar")] (is (= (:status response) 200)) (is (= (:body response) (str {"foo" "bar"})))))) (testing "basic proxy support with url encodable query parameters" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :ring-handler app-wrapped} (let [response (http-get "http://localhost:9000/hello?hello%5B%5D=hello%20world")] (is (= (:status response) 200)) (is (= (:body response) (str {"hello[]" "hello world"})))) (let [response (http-get "http://localhost:10000/hello-proxy?hello%5B%5D=hello%20world")] (is (= (:status response) 200)) (is (= (:body response) (str {"hello[]" "hello world"})))))) (testing "basic proxy support with multiple query parameters" (let [params {"foo" "bar" "baz" "lux" "hello" "world"} query "?foo=bar&baz=lux&hello=world"] (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :ring-handler app-wrapped} (let [response (http-get (str "http://localhost:9000/hello" query))] (is (= (:status response) 200)) (is (= (read-string (:body response)) params))) (let [response (http-get (str "http://localhost:10000/hello-proxy" query))] (is (= (:status response) 200)) (is (= (read-string (:body response)) params))))))) (deftest proxy-with-redirect (testing "redirect test with proxy" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:follow-redirects true} :ring-handler redirect-test-handler} (let [response (http-get "http://localhost:9000/hello/")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "proxy redirect fails if :follow-redirects not configured properly" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :ring-handler redirect-test-handler} (let [response (http-get "http://localhost:10000/hello-proxy")] (is (= (:status response) 404))))) (testing "proxy-redirect to non-target host fails" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:follow-redirects true} :ring-handler redirect-wrong-host} (let [response (http-get "http://localhost:10000/hello-proxy")] (is (= (:status response) 502))))) (testing "proxy redirect to correct host in fully qualified url works" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:follow-redirects true} :ring-handler redirect-same-host} (let [response (http-get "http://localhost:9000/hello/")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:9000/hello/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))))) (testing "proxy-redirect to non-proxied path on correct host succeeds" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:follow-redirects true} :ring-handler redirect-different-proxy-path} (let [response (http-get "http://localhost:9000/hello/")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!"))) (let [response (http-get "http://localhost:10000/hello-proxy")] (is (= (:status response) 200)) (is (= (:body response) "Hello, World!")))))) (deftest proxy-failure (testing "proxying failure - default handler" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 1 ; illegal port number :path "/hello"} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:10000/hello-proxy/world")] ;; Jetty 12 returns 502 Bad Gateway for proxy failures, which is more ;; appropriate than 500 Internal Server Error (is (= (:status response) 502))))) (testing "setting an idle timeout fails properly" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:idle-timeout 1} :ring-handler (ring-handler-with-sleep 1250)} (let [response (http-get (str "http://localhost:10000/hello-proxy"))] (is (= 504 (:status response)))))) (testing "a response before a timeout occurs succeeds" (with-target-and-proxy-servers {:target {:host "0.0.0.0" :port 9000} :proxy {:host "0.0.0.0" :port 10000} :proxy-config {:host "localhost" :port 9000 :path "/hello"} :proxy-opts {:idle-timeout 1} :ring-handler (ring-handler-with-sleep 100)} (let [response (http-get (str "http://localhost:10000/hello-proxy"))] (is (= 200 (:status response))))))) ; Modified from proxy-ring-handler (defn count-ring-handler "Increments counter if the endpoint is /goodbye" [counter req] (condp = (:uri req) "/hello/world/" {:status 200 :body (str "Hello, World!")} "/hello/" {:status 200 :body (str "Hello, You!")} "/goodbye/" {:status 200 :body (str "Goodbye! Count: " (swap! counter inc))} {:status 404 :body "count-ring-handler couldn't find the route"})) (deftest test-path-traversal-attacks (testing "proxies aren't vulnerable to basic path traversal attacks" ; goodbye-counter is used to make sure that no requests to the proxy ; endpoint, /hello-proxy, end up hitting /goodbye, as they should only be ; able to reach /hello (let [goodbye-counter (atom 0) hello-goodbye-count-ring-handler (partial count-ring-handler goodbye-counter) ; Should not succeed in hitting the goodbye endpoint bad-proxy-requests [; Encodings of '../' "https://localhost:10001/hello-proxy/../goodbye/" "https://localhost:10001/hello-proxy/%2e%2e%2fgoodbye/" "https://localhost:10001/hello-proxy/%2e%2e/goodbye/" "https://localhost:10001/hello-proxy/..%2fgoodbye/" ; Encodings of '../../' "https://localhost:10001/hello-proxy/world/../../goodbye/" "https://localhost:10001/hello-proxy/world/%2e%2e%2f%2e%2e%2fgoodbye/" "https://localhost:10001/hello-proxy/world/%2e%2e/%2e%2e/goodbye/" "https://localhost:10001/hello-proxy/world/..%2f..%2fgoodbye/"]] (with-target-and-proxy-servers {:target (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 9001}) :proxy (merge common-ssl-config {:ssl-host "0.0.0.0" :ssl-port 10001}) :proxy-config {:host "localhost" :port 9001 :path "/hello"} :ring-handler hello-goodbye-count-ring-handler} (testing "proxy is up and running" (let [response (http-get "https://localhost:10001/hello-proxy/" default-options-for-https-client)] (is (= 200 (:status response))) (is (= "Hello, You!" (:body response)))) (let [response (http-get "https://localhost:10001/hello-proxy/world/" default-options-for-https-client)] (is (= 200 (:status response))) (is (= "Hello, World!" (:body response))))) (testing "non-proxied endpoint doesn't see any traffic" (doall (for [bad-request bad-proxy-requests] (let [response (http-get bad-request default-options-for-https-client)] ;; Jetty 12 returns 400 Bad Request for path traversal attempts, ;; which is more appropriate security behavior than 404 (is (contains? #{400 404} (:status response)))))) ; Counter should still be at 0 (is (= 0 (deref goodbye-counter)))) (testing "counter is working correctly" ; A valid request to bump the counter (http-get "https://localhost:9001/goodbye/" default-options-for-https-client) (is (= 1 (deref goodbye-counter)))))))) jetty_service_test.clj000066400000000000000000001251161527232126200406210ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty-service-test (:import (org.apache.http ConnectionClosedException) (java.io IOException) (java.security.cert CRLException) (java.net SocketTimeoutException) (java.nio.file Paths Files) (java.nio.file.attribute FileAttribute) (appender TestListAppender) (javax.net.ssl SSLException) (org.slf4j MDC) (com.puppetlabs.ssl_utils SSLUtils)) (:require [clojure.test :refer :all] [clojure.string :as str] [puppetlabs.http.client.async :as async] [puppetlabs.http.client.common :as http-client-common] [puppetlabs.kitchensink.testutils.fixtures :as ks-test-fixtures] [puppetlabs.trapperkeeper.app :as tk-app] [puppetlabs.trapperkeeper.core :as tk-core] [puppetlabs.trapperkeeper.services :as tk-services] [puppetlabs.trapperkeeper.services.webserver.jetty-service :refer :all] [puppetlabs.trapperkeeper.services.watcher.filesystem-watch-service :as filesystem-watch-service] [puppetlabs.trapperkeeper.testutils.webserver :as testutils] [puppetlabs.trapperkeeper.testutils.webserver.common :refer :all] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-empty-config with-app-with-config] :as tk-bootstrap] [puppetlabs.trapperkeeper.logging :as tk-log] [puppetlabs.trapperkeeper.testutils.logging :as tk-log-testutils] [puppetlabs.trapperkeeper.services.webserver.jetty-core :as core] [schema.core :as schema] [schema.test :as schema-test] [puppetlabs.kitchensink.core :as ks] [ring.middleware.params :as ring-params] [me.raynes.fs :as fs])) (use-fixtures :once ks-test-fixtures/with-no-jvm-shutdown-hooks schema-test/validate-schemas testutils/assert-clean-shutdown (fn [f] (tk-log/reset-logging) (f))) (def default-server-config {:webserver {:foo {:port 8080} :bar {:port 9000 :default-server true}}}) (def no-default-config {:webserver {:foo {:port 8080} :bar {:port 9000}}}) (def static-content-single-config {:webserver {:port 8080 :static-content [{:resource "./dev-resources" :path "/resources" :follow-links true}, {:resource "./dev-resources" :path "/resources2"}]}}) (def static-content-multi-config {:webserver {:foo {:port 8080 :static-content [{:resource "./dev-resources" :path "/resources"}, {:resource "./dev-resources" :path "/resources2"}]} :bar {:port 9000 :static-content [{:resource "./dev-resources" :path "/resources"}, {:resource "./dev-resources" :path "/resources2"}]}}}) (defmacro ssl-exception-thrown? [& body] `(try ~@body (throw (IllegalStateException. "Expected SSL Exception to be thrown!")) (catch ConnectionClosedException e# true) (catch SSLException e# true) (catch IOException e# (if (= "Connection reset by peer" (.getMessage e#)) true (throw e#))))) (def unauthorized-pem-options-for-https (-> default-options-for-https-client (assoc :ssl-cert "./dev-resources/config/jetty/ssl/certs/unauthorized.pem") (assoc :ssl-key "./dev-resources/config/jetty/ssl/private_keys/unauthorized.pem"))) (def hello-path "/hi_world") (def hello-body "Hi World") (defn hello-handler [req] {:status 200 :body hello-body}) (def mdc-path "/mdc") (defn mdc-handler [req] (let [mdc-key (get-in req [:params "mdc_key"])] (case (:request-method req) :get {:status 200 :body (MDC/get mdc-key)} :put (do (MDC/put mdc-key (slurp (:body req))) {:status 201 :body "OK."})))) (tk-core/defservice hello-webservice [[:WebserverService add-ring-handler]] (init [this context] (add-ring-handler hello-handler hello-path) (add-ring-handler (ring-params/wrap-params mdc-handler) mdc-path) context)) (defn validate-ring-handler ([base-url config] (validate-ring-handler base-url config {:as :text} :default)) ([base-url config http-get-options] (validate-ring-handler base-url config http-get-options :default)) ([base-url config http-get-options server-id] (with-app-with-config app [jetty-service hello-webservice] config (let [response (http-get (format "%s%s/" base-url hello-path) http-get-options)] (is (= (:status response) 200)) (is (= (:body response) hello-body)))))) (defn validate-ring-handler-default ([base-url config] (validate-ring-handler-default base-url config {:as :text})) ([base-url config http-get-options] (with-app-with-config app [jetty-service hello-webservice] config (let [response (http-get (format "%s%s/" base-url hello-path) http-get-options)] (is (= (:status response) 200)) (is (= (:body response) hello-body)))))) (deftest basic-ring-test (testing "ring request over http succeeds" (validate-ring-handler "http://localhost:8080" jetty-plaintext-config))) (deftest basic-default-ring-test (testing "ring request over http succeeds with default add-ring-handler" (validate-ring-handler-default "http://localhost:8080" jetty-plaintext-config)) (testing "ring request on single server with new syntax over http succeeds" (validate-ring-handler "http://localhost:8080" {:webserver {:default {:port 8080 :default-server true}}} {:as :text} :default))) (deftest ring-handler-nil-response-returns-404 (testing "ring handler returning nil results in 404 response" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (tk-app/get-service app :WebserverService) nil-handler (fn [req] nil)] (add-ring-handler s nil-handler "/nil-route") (let [response (http-get "http://localhost:8080/nil-route/")] (is (= 404 (:status response)))))))) (deftest single-server-jmx-cleanup-test (testing "no jetty mbeancontainers are registered prior to starting servers" (is (empty? (testutils/get-jetty-mbean-object-names)))) (with-app-with-config app [jetty-service] jetty-plaintext-config (testing "one jetty mbean container is registered per server" (is (= 1 (count (testutils/get-jetty-mbean-object-names)))))) (testing "jetty mbean containers are unregistered after server is stopped" (is (empty? (testutils/get-jetty-mbean-object-names))))) (deftest multiserver-ring-test (testing "no jetty mbeancontainers are registered prior to starting servers" (is (empty? (testutils/get-jetty-mbean-object-names)))) (testing "ring requests on multiple servers succeed" (with-app-with-config app [jetty-service] jetty-multiserver-plaintext-config (let [s (tk-app/get-service app :WebserverService) add-ring-handler (partial add-ring-handler s)] (add-ring-handler hello-handler hello-path {:server-id :foo}) (add-ring-handler hello-handler hello-path {:server-id :bar}) (let [response1 (http-get "http://localhost:8080/hi_world/" {:as :text}) response2 (http-get "http://localhost:8085/hi_world/" {:as :text})] (is (= (:status response1) 200)) (is (= (:status response2) 200)) (is (= (:body response1) hello-body)) (is (= (:body response2) hello-body))) (testing "one jetty mbean container is registered per server" (is (= 2 (count (testutils/get-jetty-mbean-object-names)))))))) (testing "jetty mbean containers are unregistered after server is stopped" (is (empty? (testutils/get-jetty-mbean-object-names)))) (testing "ring request succeeds with multiple servers and default add-ring-handler" (validate-ring-handler-default "http://localhost:8080" jetty-multiserver-plaintext-config))) (deftest port-test (testing "webserver bootstrap throws IllegalArgumentException when neither port nor ssl-port specified in the config" (is (thrown-with-msg? IllegalArgumentException #"Either host, port, ssl-host, or ssl-port must be specified" (tk-log-testutils/with-test-logging (with-app-with-empty-config app [jetty-service]))) "Did not encounter expected exception when no port specified in config"))) (deftest ssl-success-test (testing "ring request over SSL successful for both .jks and .pem implementations with the server's client-auth setting not set and the client configured provide a certificate which the CA can validate" ; Note that if the 'client-auth' setting is not set that the server ; should default to 'need' to validate the client certificate. In this ; case, the validation should be successful because the client is ; providing a certificate which the CA can validate. (doseq [config [(jetty-ssl-jks-config) jetty-ssl-pem-config]] (validate-ring-handler "https://localhost:8081" config default-options-for-https-client))) (testing "ring request over SSL succeeds with a server client-auth setting of 'need' and the client configured to provide a certificate which the CA can validate" (validate-ring-handler "https://localhost:8081" jetty-ssl-client-need-config default-options-for-https-client)) (testing "ring request over SSL succeeds with a server client-auth setting of 'want' and the client configured to provide a certificate which the CA can validate" (validate-ring-handler "https://localhost:8081" jetty-ssl-client-want-config default-options-for-https-client)) (testing "ring request over SSL succeeds with a server client-auth setting of 'want' and the client configured to not provide a certificate" (validate-ring-handler "https://localhost:8081" jetty-ssl-client-want-config (dissoc default-options-for-https-client :ssl-cert :ssl-key))) (testing "ring request over SSL succeeds with a server client-auth setting of 'none' and the client configured to provide a certificate which the CA can validate" (validate-ring-handler "https://localhost:8081" jetty-ssl-client-none-config default-options-for-https-client)) (testing "ring request over SSL succeeds with a server client-auth setting of 'none' and the client configured to not provide a certificate" (validate-ring-handler "https://localhost:8081" jetty-ssl-client-none-config (dissoc default-options-for-https-client :ssl-cert :ssl-key))) (testing "ring request over SSL succeeds with a server client-auth setting of 'none' and the client configured to provide a certificate which the CA cannot validate" (validate-ring-handler "https://localhost:8081" jetty-ssl-client-none-config unauthorized-pem-options-for-https)) (testing "ring request over SSL succeeds with the server configured to use both an ssl-cert and an ssl-cert-chain" (validate-ring-handler "https://localhost:8081" (assoc-in jetty-ssl-client-need-config [:webserver :ssl-cert-chain] (:ssl-ca-cert default-options-for-https-client)) default-options-for-https-client))) (deftest ssl-failure-test (testing "ring request over SSL fails with the server's client-auth setting not set and the client configured to provide a certificate which the CA cannot validate" ; Note that if the 'client-auth' setting is not set that the server ; should default to 'need' to validate the client certificate. In this ; case, the validation should fail because the client is providing a ; certificate which the CA cannot validate. (is (ssl-exception-thrown? (validate-ring-handler "https://localhost:8081" jetty-ssl-pem-config unauthorized-pem-options-for-https)))) (testing "ring request over SSL fails with the server's client-auth setting not set and the client configured to not provide a certificate" ; Note that if the 'client-auth' setting is not set that the server ; should default to 'need' to validate the client certificate. In this ; case, the validation should fail because the client is not providing a ; certificate (is (ssl-exception-thrown? (validate-ring-handler "https://localhost:8081" jetty-ssl-pem-config (dissoc default-options-for-https-client :ssl-cert :ssl-key))))) (testing "ring request over SSL fails with a server client-auth setting of 'need' and the client configured to provide a certificate which the CA cannot validate" (is (ssl-exception-thrown? (validate-ring-handler "https://localhost:8081" jetty-ssl-client-need-config unauthorized-pem-options-for-https)))) (testing "ring request over SSL fails with a server client-auth setting of 'need' and the client configured to not provide a certificate" (is (ssl-exception-thrown? (validate-ring-handler "https://localhost:8081" jetty-ssl-client-need-config (dissoc default-options-for-https-client :ssl-cert :ssl-key))))) (testing "ring request over SSL fails with a server client-auth setting of 'want' and the client configured to provide a certificate which the CA cannot validate" (is (ssl-exception-thrown? (validate-ring-handler "https://localhost:8081" jetty-ssl-client-want-config unauthorized-pem-options-for-https))))) (deftest crl-success-test (testing (str "ring request over SSL succeeds when no client certificates " "have been revoked") (validate-ring-handler "https://localhost:8081" (assoc-in jetty-ssl-client-need-config [:webserver :ssl-crl-path] "./dev-resources/config/jetty/ssl/crls/crls_none_revoked.pem") default-options-for-https-client)) (testing (str "ring request over SSL succeeds when a different client " "certificate than the one used in the request has been revoked") (validate-ring-handler "https://localhost:8081" (assoc-in jetty-ssl-client-need-config [:webserver :ssl-crl-path] (str "./dev-resources/config/jetty/ssl/crls/" "crls_localhost-compromised_revoked.pem")) default-options-for-https-client))) (deftest crl-failure-test (testing (str "ring request over SSL fails when the client certificate has " "been revoked") (is (ssl-exception-thrown? (validate-ring-handler "https://localhost:8081" (assoc-in jetty-ssl-client-need-config [:webserver :ssl-crl-path] "./dev-resources/config/jetty/ssl/crls/crls_localhost_revoked.pem") default-options-for-https-client)))) ;; the Bouncy Castle FIPS provider does not throw an exception for this use-case ;; whereas the SunX509 provider does. (when-not (SSLUtils/isFIPS) (testing (str "jetty throws startup exception if non-CRL PEM is specified " "as ssl-crl-path") (tk-log-testutils/with-test-logging (is (thrown? CRLException (with-app-with-config app [jetty-service] (assoc-in jetty-ssl-client-need-config [:webserver :ssl-crl-path] "./dev-resources/config/jetty/ssl/certs/ca.pem"))))))) (testing (str "jetty throws startup exception if ssl-crl-path refers to a " "non-existent file") (tk-log-testutils/with-test-logging (is (thrown-with-msg? IllegalArgumentException #"Non-readable path specified for ssl-crl-path option" (with-app-with-config app [jetty-service] (assoc-in jetty-ssl-client-need-config [:webserver :ssl-crl-path] "./dev-resources/config/jetty/ssl/crls/crls_bogus.pem"))))))) (deftest crl-reloaded-without-server-restart-test (let [tmp-dir (ks/temp-dir) tmp-file (fs/file tmp-dir "mycrl.pem") get-request #(http-get (str "https://localhost:8081" hello-path) default-options-for-https-client)] (fs/copy "./dev-resources/config/jetty/ssl/crls/crls_none_revoked.pem" tmp-file) (with-app-with-config app [jetty-service hello-webservice filesystem-watch-service/filesystem-watch-service] (assoc-in jetty-ssl-client-need-config [:webserver :ssl-crl-path] (str tmp-file)) (testing "request to jetty successful before cert revoked" (let [response (get-request)] (is (= (:status response) 200)) (is (= (:body response) hello-body)))) (testing "request fails after cert revoked" ;; Sleep a bit to wait for the file watcher to be ready to poll/notify ;; for change events on the CRL. Ideally wouldn't have to do this but ;; seems like the initial event notification doesn't propagate if the ;; file is changed too soon after initialization. (Thread/sleep 1000) (fs/copy "./dev-resources/config/jetty/ssl/crls/crls_localhost_revoked.pem" tmp-file) (is (loop [times 30] (cond (try (ssl-exception-thrown? (get-request)) (catch IllegalStateException _ false)) true (zero? times) (ssl-exception-thrown? (get-request)) :else (do (Thread/sleep 500) (recur (dec times)))))))))) (defn boot-service-and-jetty-with-default-config [service] (tk-core/boot-services-with-config [service jetty-service] jetty-plaintext-config)) (defn boot-service-and-jetty-with-multiserver-config [service] (tk-core/boot-services-with-config [service jetty-service] jetty-multiserver-plaintext-config)) (defn get-jetty-server-from-app-context ([app] (get-jetty-server-from-app-context app :default)) ([app server-id] (-> (tk-app/get-service app :WebserverService) (tk-services/service-context) (:jetty-servers) (server-id) (:server)))) (deftest jetty-and-dependent-service-shutdown-after-service-error (testing (str "jetty and any dependent services are shutdown after a" "service throws an error from its start function") (tk-log-testutils/with-test-logging (let [shutdown-called? (atom false) test-service (tk-services/service [[:WebserverService]] (start [this context] (throw (Throwable. "oops")) context) (stop [this context] (reset! shutdown-called? true) context)) app (boot-service-and-jetty-with-default-config test-service) jetty-server (get-jetty-server-from-app-context app)] (is (.isStarted jetty-server) "Jetty server was never started before call to run-app") (is (not (.isStopped jetty-server)) "Jetty server was stopped before call to run-app") (is (thrown-with-msg? Throwable #"oops" (tk-core/run-app app)) "tk run-app did not die with expected exception.") (is (true? @shutdown-called?) "Service shutdown was not called.") (is (.isStopped jetty-server) "Jetty server was not stopped after call to run-app.")))) (testing (str "jetty and any dependent services are shutdown after a" "service throws an error from its start function" "in a multi-server set-up") (tk-log-testutils/with-test-logging (let [shutdown-called? (atom false) test-service (tk-services/service [[:WebserverService]] (start [this context] (throw (Throwable. "oops")) context) (stop [this context] (reset! shutdown-called? true) context)) app (boot-service-and-jetty-with-multiserver-config test-service) jetty-server1 (get-jetty-server-from-app-context app :foo) jetty-server2 (get-jetty-server-from-app-context app :bar)] (is (.isStarted jetty-server1) "First Jetty server was never started before call to run-app") (is (.isStarted jetty-server2) "Second Jetty server was never started before call to run-app") (is (not (.isStopped jetty-server1)) "First Jetty server was stopped before call to run-app") (is (not (.isStopped jetty-server2)) "Second Jetty server was stopped before call to run-app") (is (thrown-with-msg? Throwable #"oops" (tk-core/run-app app)) "tk run-app did not die with expected exception.") (is (true? @shutdown-called?) "Service shutdown was not called.") (is (.isStopped jetty-server1) "First Jetty server was not stopped after call to run-app.") (is (.isStopped jetty-server2) "Second Jetty server was not stopped after call to run-app.")))) (testing (str "jetty server instance never attached to the service context " "and dependent services are shutdown after a service throws " "an error from its init function") (tk-log-testutils/with-test-logging (let [shutdown-called? (atom false) test-service (tk-services/service [[:WebserverService]] (init [this context] (throw (Throwable. "oops")) context) (stop [this context] (reset! shutdown-called? true) context)) app (boot-service-and-jetty-with-default-config test-service) jetty-server (get-jetty-server-from-app-context app)] (is (thrown-with-msg? Throwable #"oops" (tk-core/run-app app)) "tk run-app did not die with expected exception.") (is (nil? jetty-server) (str "Jetty server was unexpectedly attached to the service " "context.")) (is (true? @shutdown-called?) "Service shutdown was not called.")))) (testing (str "attempt to launch second jetty server on same port as " "already running jetty server fails with IOException without " "placing second jetty server instance on app context") (tk-log-testutils/with-test-logging (let [first-app (tk-core/boot-services-with-config [jetty-service] jetty-plaintext-config)] (try (let [second-app (tk-core/boot-services-with-config [jetty-service] jetty-plaintext-config) second-jetty-server (get-jetty-server-from-app-context second-app)] (is (logged? #"^Encountered error starting web server, so shutting down") "Didn't find log message for port bind error") (is (nil? second-jetty-server) "Jetty server was unexpectedly attached to the service context") (is (thrown? IOException (tk-core/run-app second-app)) "tk run-app did not die with expected exception.")) (finally (tk-app/stop first-app))))))) (deftest default-server-test (testing (str "specifying a config in the old format will start a server with " "a server-id of :default") (let [app (tk-core/boot-services-with-config [jetty-service] jetty-plaintext-config) context-list (-> (tk-app/get-service app :WebserverService) (tk-services/service-context) (:jetty-servers)) jetty-server (get-jetty-server-from-app-context app)] (is (contains? context-list :default) "the default key was not added to the context list") (is (nil? (schema/check core/ServerContext (:default context-list))) "the value of the default key is not a valid server context") (is (.isStarted jetty-server) "the default server was never started") (tk-app/stop app)))) (deftest large-request-test ;; This changed from 413 to 431 in https://github.com/eclipse/jetty.project/commit/e53ea55f480a959a2f1f5e2dbdbfc689d61c94a6 (testing (str "request to Jetty fails with a 431 error if the request header " "is too large and a larger one is not set") (with-app-with-config app [jetty-service hello-webservice] jetty-plaintext-config (tk-log-testutils/with-test-logging (let [response (http-get "http://localhost:8080/hi_world" {:headers {"Cookie" absurdly-large-cookie} :as :text})] (is (= (:status response) 431)))))) (testing (str "request to Jetty succeeds with a large cookie if the request header " "size is properly set") (with-app-with-config app [jetty-service] jetty-plaintext-large-request-config (let [s (tk-app/get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) body "Hi World" path "/hi_world" ring-handler (fn [req] {:status 200 :body (str body ((:headers req) "cookie"))})] (add-ring-handler ring-handler path) (let [response (http-get "http://localhost:8080/hi_world" {:headers {"Cookie" absurdly-large-cookie} :as :text})] (is (= (:status response) 200)) (is (= (:body response) (str "Hi World" absurdly-large-cookie)))))))) (deftest default-server-test (testing "handler added to user-specified default server if no server-id is given" (with-app-with-config app [jetty-service hello-webservice] default-server-config (let [response (http-get "http://localhost:9000/hi_world")] (is (= 200 (:status response))) (is (= (:body response) hello-body))))) (testing (str "exception thrown if user does not specify a " "default server and no server-id is given") (with-app-with-config app [jetty-service] no-default-config (let [s (tk-app/get-service app :WebserverService) add-ring-handler (partial add-ring-handler s)] (is (thrown? IllegalArgumentException (add-ring-handler hello-handler hello-path))))))) (deftest static-content-config-test (let [logback (slurp "./dev-resources/logback.xml")] (testing "static content can be specified in a single-server configuration" (with-app-with-config app [jetty-service] static-content-single-config (let [response (http-get "http://localhost:8080/resources/logback.xml") response2 (http-get "http://localhost:8080/resources2/logback.xml")] (is (= (:status response) 200)) (is (= (:body response) logback)) (is (= (:status response2) 200)) (is (= (:body response2) logback))))) (testing "static content can be specified in a multi-server configuration" (with-app-with-config app [jetty-service] static-content-multi-config (let [response (http-get "http://localhost:8080/resources/logback.xml") response2 (http-get "http://localhost:8080/resources2/logback.xml")] (is (= (:status response) 200)) (is (= (:body response) logback)) (is (= (:status response2) 200)) (is (= (:body response2) logback))) (let [response (http-get "http://localhost:9000/resources/logback.xml") response2 (http-get "http://localhost:9000/resources2/logback.xml")] (is (= (:status response) 200)) (is (= (:body response) logback)) (is (= (:status response2) 200)) (is (= (:body response2) logback))))))) (deftest static-content-symlink-test (let [logback (slurp (str dev-resources-dir "logback.xml")) link (Paths/get (str dev-resources-dir "logback-link.xml") (into-array java.lang.String [])) file (Paths/get "logback.xml" (into-array java.lang.String []))] (try (Files/createSymbolicLink link file (into-array FileAttribute [])) (testing "static content can be served with symlinks when option specified in config" (with-app-with-config app [jetty-service] static-content-single-config (let [response (http-get "http://localhost:8080/resources/logback.xml") response2 (http-get "http://localhost:8080/resources/logback-link.xml")] (is (= (:status response) 200)) (is (= (:body response) logback)) (is (= (:status response2) 200)) (is (= (:body response2) logback))))) (testing "static content cannot be served with symlinks if option not set" (with-app-with-config app [jetty-service] static-content-single-config (let [response (http-get "http://localhost:8080/resources2/logback.xml") response2 (http-get "http://localhost:8080/resources2/logback-link.xml")] (is (= (:status response) 200)) (is (= (:body response) logback)) (is (= (:status response2) 404))))) (finally (Files/delete link))))) ;; PE-37252 temporarily disable logging tests (deftest request-logging-test (with-app-with-config app [jetty-service hello-webservice] {:webserver {:port 8080 ;; Restrict the number of threads available to the webserver ;; so we can easily test whether thread-local values in the ;; MDC are cleaned up. :acceptor-threads 1 :selector-threads 1 ; You actually end up with 2 threads. :max-threads 4 :access-log-config "./dev-resources/puppetlabs/trapperkeeper/services/webserver/request-logging.xml"}} (testing "request logging occurs when :access-log-config is configured" (with-test-access-logging (http-get "http://localhost:8080/hi_world/") ; Logging is done in a separate thread from Jetty and this test. As a result, ; we have to sleep the thread to avoid a race condition. (Thread/sleep 10) (let [list (TestListAppender/list)] (is (re-find #"\"GET /hi_world/ HTTP/1.1\" 200" (first list)))))) (testing "Mapped Diagnostic Context values are available to the access logger" (with-test-access-logging (http-put "http://localhost:8080/mdc?mdc_key=mdc-test" {:body "hello"}) (Thread/sleep 10) (let [list (TestListAppender/list)] (is (str/ends-with? (first list) "hello\n"))))) (testing "Mapped Diagnostic Context values are cleared after each request" (http-put "http://localhost:8080/mdc?mdc_key=mdc-persist" {:body "foo"}) ;; Loop to ensure we hit all threads. (let [responses (for [n (range 0 10)] (http-get "http://localhost:8080/mdc?mdc_key=mdc-persist"))] (is (every? #(not= "foo" %) (map :body responses))))))) (deftest graceful-shutdown-test (testing "jetty webservers shut down gracefully by default" (with-app-with-config app [jetty-service] jetty-plaintext-config (let [s (tk-app/get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) in-request-handler (promise) ring-handler (fn [_] (deliver in-request-handler true) (Thread/sleep 3000) {:status 200 :body "Hello, World!"})] (add-ring-handler ring-handler "/hello") (with-open [async-client (async/create-client {})] (let [response (http-client-common/get async-client "http://localhost:8080/hello" {:as :text :headers {"Accept-Encoding" "identity"}})] @in-request-handler (tk-app/stop app) (is (= (:status @response) 200)) (is (= (:body @response) "Hello, World!"))))))) (testing "jetty's stop timeout can be changed from config" (with-app-with-config app [jetty-service] {:webserver {:port 8080 :shutdown-timeout-seconds 1}} (let [s (tk-app/get-service app :WebserverService) add-ring-handler (partial add-ring-handler s) in-request-handler (promise) ring-handler (fn [_] (deliver in-request-handler true) (Thread/sleep 2000) {:status 200 :body "Hello, World!"})] (add-ring-handler ring-handler "/hello") (with-open [async-client (async/create-client {})] (let [response (http-client-common/get async-client "http://localhost:8080/hello" {:as :text})] @in-request-handler (tk-log-testutils/with-test-logging (tk-app/stop app)) (is (not (nil? (:error @response))))))))) ; Per [TK-437](https://tickets.puppetlabs.com/browse/TK-437) we've been having issues ; with this test randomly hanging, but the fixes applied for TK-437 didn't seem to resolve ; the issue. This test is disabled until we can work out a reliable fix. ; ; (testing "no graceful shutdown when stop timeout is set to 0" ; (let [response (atom nil)] ; ;; For this test, an active web request should exist at the time the ; ;; webserver service is stopped. Because the shutdown timeout is set to ; ;; 0, though, the request should be terminated immediately as the ; ;; webserver service is shut down, without waiting for ring handler ; ;; to complete the request. ; (with-open [async-client (async/create-client ; ;; Setting the socket timeout to something much ; ;; larger than the sleep delay done in the ring ; ;; handler below. This timeout allows the HTTP ; ;; client request to not hang the test ; ;; indefinitely in the event of an unexpected ; ;; test failure. ; {:socket-timeout-milliseconds 120000})] ; (tk-log-testutils/with-test-logging ; (with-app-with-config ; app ; [jetty-service] ; {:webserver {:port 8080 :shutdown-timeout-seconds 0}} ; (let [s (tk-app/get-service app :WebserverService) ; add-ring-handler (partial add-ring-handler s) ; in-request-handler (promise) ; ring-handler (fn [_] ; (deliver in-request-handler true) ; ;; Sleeping for a long time to allow an HTTP ; ;; request to still be active at the point the ; ;; webserver is shutdown ; (Thread/sleep 60000) ; {:status 200 :body "Hello, World!"})] ; (add-ring-handler ring-handler "/hello") ; (reset! response (http-client-common/get ; async-client ; "http://localhost:8080/hello" ; {:as :text})) ; @in-request-handler))) ; ;; The web server should have been stopped by the time we get here. ; ;; Depending upon timing, the Jetty webserver may provide an HTTP 404 ; ;; response or just terminate the socket for the web request which could ; ;; not be completed, which should cause a ConnectionClosedException to ; ;; be thrown. ; ;; ; ;; Note that per TK-437, we have occasionally seen this assertion fail ; ;; due to a SocketTimeoutException being thrown. In this case, there ; ;; appears to be a timing-related bug in Jetty where the server socket ; ;; isn't closed down even though the server otherwise appears to have ; ;; been stopped properly - leaving the server-side of the connection in ; ;; an indefinite CLOSE_WAIT state. ; (let [resp (deref (deref response)) ; error (:error resp)] ; (is (or ; (instance? ConnectionClosedException error) ; (= 404 (:status resp))) ; (str "request did not error as expected. response: " resp)))))) (testing "tk app can still restart even if stop timeout expires" (let [in-request-handler? (promise) unblock-request? (promise) sleepy-service (tk-core/service [[:WebserverService add-ring-handler]] (init [this context] (add-ring-handler (fn [_] (deliver in-request-handler? true) @unblock-request? {:status 200 :body hello-body}) hello-path) context))] (tk-log-testutils/with-test-logging (with-app-with-config app [jetty-service sleepy-service] {:webserver {:port 8080 :shutdown-timeout-seconds 1}} (with-open [async-client (async/create-client {})] (let [response (http-client-common/get async-client "http://localhost:8080/hi_world" {:as :text})] @in-request-handler? (tk-app/restart app) (is (not (nil? (:error @response))))) (deliver unblock-request? true) (let [response (http-client-common/get async-client "http://localhost:8080/hi_world" {:as :text})] (is (= 200 (:status @response))) (is (= hello-body (:body @response)))))))))) (deftest double-stop-test (testing "if the stop lifecycle is called more than once, we handle that gracefully and quietly" (tk-log-testutils/with-logged-event-maps log-events (let [app (tk-bootstrap/bootstrap-services-with-config [jetty-service] {:webserver {:port 8080}})] (tk-app/stop app) (tk-app/stop app)) ;; we previously had a bug where we could try to unregister mbeans multiple ;; times if our tk-j9 stop lifecycle function was called more than once. ;; in that case, Jetty would log tons of nasty exceptions at warning level. ;; this test just validates that that is not happening. (let [log-event-filter #(or (= :warn (:level %)) (= :error (:level %))) mbean-err-logs (filter log-event-filter @log-events)] (is (= 0 (count mbean-err-logs))))))) (deftest warn-if-sslv3-supported-test (letfn [(start-server [ssl-protocols] (let [config (if ssl-protocols (assoc-in jetty-ssl-pem-config [:webserver :ssl-protocols] ssl-protocols) jetty-ssl-pem-config)] (with-app-with-config app [jetty-service] config)))] (testing "warns if SSLv3 is in the protocol list" (tk-log-testutils/with-test-logging (start-server ["SSLv3" "TLSv1"]) (is (logged? #"known vulnerabilities")))) (testing "warns regardless of case" (tk-log-testutils/with-test-logging (start-server ["sslv3"]) (is (logged? #"known vulnerabilities")))) (testing "does not warn if sslv3 is not in the protocol list" (tk-log-testutils/with-log-output logs (start-server ["TLSv1"]) (is (= 0 (count (tk-log-testutils/logs-matching #"known vulnerabilities" @logs)))))) (testing "does not warn with default settings" (tk-log-testutils/with-log-output logs (start-server nil) (is (= 0 (count (tk-log-testutils/logs-matching #"known vulnerabilities" @logs)))))))) (deftest sslv3-support-test (testing "SSLv3 is not supported by default" (with-app-with-config app [jetty-service hello-webservice] jetty-ssl-pem-config (let [test-fn (fn [] (http-get "https://localhost:8081/hi_world" (merge default-options-for-https-client {:ssl-protocols ["SSLv3"]})))] (is (thrown? SSLException (test-fn)))))) (testing "SSLv3 is not supported even when configured" (tk-log-testutils/with-test-logging (with-app-with-config app [jetty-service hello-webservice] (-> jetty-ssl-pem-config (assoc-in [:webserver :ssl-protocols] ["SSLv3"]) (assoc-in [:webserver :cipher-suites] ["TLS_RSA_WITH_AES_128_CBC_SHA"])) (is (logged? #"contains SSLv3, a protocol with known vulnerabilities; ignoring")) (is (logged? #"When `ssl-protocols` is empty, a default of")) (let [test-fn (fn [] (http-get "https://localhost:8081/hi_world" (merge default-options-for-https-client {:ssl-protocols ["SSLv3"]})))] (is (thrown? SSLException (test-fn)))))))) normalized_uri_helpers_test.clj000066400000000000000000000157561527232126200425170ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.normalized-uri-helpers-test (:import (jakarta.servlet.http HttpServletRequest)) (:require [clojure.test :refer :all] [puppetlabs.trapperkeeper.services.webserver.normalized-uri-helpers :as normalized-uri-helpers])) (defn normalize-uri-path-for-string [uri] (normalized-uri-helpers/normalize-uri-path (reify HttpServletRequest (getRequestURI [_] uri)))) (deftest normalize-uris-with-no-special-characters-tests (testing "uris with no special characters are preserved after normalization" (is (= "" (normalize-uri-path-for-string ""))) (is (= "/" (normalize-uri-path-for-string "/"))) (is (= "/foo" (normalize-uri-path-for-string "/foo"))) (is (= "/foo/bar" (normalize-uri-path-for-string "/foo/bar"))))) (deftest normalize-uris-with-plus-signs-in-path-segments-tests (testing (str "non-percent encoded plus signs in uri path segments are " "preserved after normalization") (is (= "/foo+bar" (normalize-uri-path-for-string "/foo+bar"))) (is (= "/foo/bar+baz+bim" (normalize-uri-path-for-string "/foo/bar+baz+bim")))) (testing (str "percent encoded plus signs in uri path segments are " "properly decoded after normalization") (is (= "/foo+bar" (normalize-uri-path-for-string "/foo%2Bbar"))) (is (= "/foo/bar+baz+bim" (normalize-uri-path-for-string "/foo/bar%2Bbaz%2Bb%69m"))))) (deftest normalize-uris-with-params-in-path-segments-tests (testing (str "non-percent encoded parameters in uri path segments are " "chopped off after normalization") (is (= "/foo" (normalize-uri-path-for-string "/foo;foo=chump"))) (is (= "/foo/bar/baz" (normalize-uri-path-for-string "/foo/bar;bar=chocolate/baz;baz=bim")))) (testing (str "percent-encoded parameters in uri path segments are properly " "decoded after normalization") (is (= "/foo;foo=chump" (normalize-uri-path-for-string "/foo%3Bfoo=chump"))) (is (= "/foo/bar;bar=chocolate/baz;baz=bim" (normalize-uri-path-for-string "/foo/bar%3Bbar=chocolate/baz%3Bbaz=b%69m"))))) (deftest normalize-uris-with-percent-encoded-characters-tests (testing (str "percent-encoded characters are properly decoded after " "normalization") (is (= "/foo" (normalize-uri-path-for-string "/%66oo"))) (is (= "/foo/b a r" (normalize-uri-path-for-string "/foo%2f%62%20a%20%72")))) (testing "malformed percent-encoded character throws exception" (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/%b%a%r"))))) (deftest normalize-uris-with-relative-paths-tests (testing "non percent-encoded relative paths are normalized as an error" (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "."))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string ".."))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/."))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/.."))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/."))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/.."))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/./bar"))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/../bar")))) (testing "percent-encoded relative paths are normalized as an error" (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "%2E"))) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "%2E%2E") )) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/%2E") )) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/%2E%2E") )) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/%2E") )) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/%2E%2E") )) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/%2E/bar") )) (is (thrown? IllegalArgumentException (normalize-uri-path-for-string "/foo/%2E%2E/bar") ))) (testing (str "period characters not representing relative paths are not " "normalized as an error") (is (= "/foo/.bar" (normalize-uri-path-for-string "/foo/.bar"))) (is (= "/foo/..bar" (normalize-uri-path-for-string "/foo/..bar"))) (is (= "/foo/bar." (normalize-uri-path-for-string "/foo/bar."))) (is (= "/foo/bar.." (normalize-uri-path-for-string "/foo/bar.."))) (is (= "/foo/bar.../baz" (normalize-uri-path-for-string "/foo/bar.../baz"))) (is (= "/foo/.bar" (normalize-uri-path-for-string "/foo/%2Ebar"))) (is (= "/foo/..bar" (normalize-uri-path-for-string "/foo/%2E%2Ebar"))) (is (= "/foo/bar." (normalize-uri-path-for-string "/foo/bar%2E"))) (is (= "/foo/bar.." (normalize-uri-path-for-string "/foo/bar%2E%2E"))) (is (= "/foo/bar/.../baz" (normalize-uri-path-for-string "/foo/bar/%2E%2E%2E/baz"))))) (deftest normalize-uri-with-overlong-utf8-chars-tests (testing (str "utf-8 characters with overlong encodings are substituted " "with replacement characters") ;; In Jetty 12, invalid/overlong UTF-8 sequences are replaced with ;; the Unicode replacement character (U+FFFD) instead of literal bytes. ;; This achieves the same security goal as the old behavior - preventing ;; overlong encodings from being decoded as path traversal characters. (is (= "��" (normalize-uri-path-for-string "%C0%AE"))) (is (= "/foo/��/��" (normalize-uri-path-for-string "/foo/%C0%AE/%C0%AE"))))) (deftest normalize-uris-with-redundant-slashes-tests (testing "uris with redundant slashes are removed" (is (= "/" (normalize-uri-path-for-string "//"))) (is (= "/foo" (normalize-uri-path-for-string "//foo"))) (is (= "/foo" (normalize-uri-path-for-string "///foo"))) (is (= "/foo/bar" (normalize-uri-path-for-string "/foo//bar"))) (is (= "/foo/bar/" (normalize-uri-path-for-string "/foo//bar///"))))) (deftest normalize-uris-with-percent-decoding-and-slash-removal (testing (str "uris with both percent-encoded characters and redundant " "slashes are properly normalized") (is (= "/foo/b a r" (normalize-uri-path-for-string "/%66oo%2f%2f%2f%62%20a r"))))) OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/testutils/000077500000000000000000000000001527232126200324735ustar00rootroot00000000000000webrouting/000077500000000000000000000000001527232126200346015ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/testutilscommon.clj000066400000000000000000000013151527232126200365630ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/testutils/webrouting(ns puppetlabs.trapperkeeper.testutils.webrouting.common (:require [puppetlabs.http.client.sync :as http-client])) (defn http-get ([url] (http-get url {:as :text})) ([url options] (http-client/get url options))) (def webrouting-plaintext-config {:webserver {:port 8080} :web-router-service {:puppetlabs.trapperkeeper.services.webrouting.webrouting-service-handlers-test/test-dummy "/foo" :puppetlabs.bar/bar-service "/bar"}}) (def default-options-for-https-client {:ssl-cert "./dev-resources/config/jetty/ssl/certs/localhost.pem" :ssl-key "./dev-resources/config/jetty/ssl/private_keys/localhost.pem" :ssl-ca-cert "./dev-resources/config/jetty/ssl/certs/ca.pem" :as :text}) webserver.clj000066400000000000000000000065641527232126200351250ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/testutils(ns puppetlabs.trapperkeeper.testutils.webserver (:require [puppetlabs.trapperkeeper.services.webserver.jetty-core :as jetty] [clojure.test :refer [is]] [clojure.java.jmx :as jmx]) (:import (javax.management ObjectName) (java.lang.management ManagementFactory))) (defmacro with-test-webserver-and-config "Constructs and starts an embedded Jetty on a random port with a custom configuration and evaluates `body` inside a try/finally block that takes care of tearing down the webserver. `app` - The ring application the webserver should serve `port-var` - Inside of `body`, the variable named `port-var` contains the port number the webserver is listening on `config` - Configuration to use for the webserver Example: (let [app (constantly {:status 200 :headers {} :body \"OK\"})] (with-test-webserver app port {:request-header-max-size 1024} ;; Hit the embedded webserver (http-client/get (format \"http://localhost:%s\" port))))" [app port-var config & body] `(let [srv# (jetty/start-webserver! (jetty/initialize-context) (assoc ~config :port 0)) _# (jetty/add-ring-handler srv# ~app "/" true false) ~port-var (-> (:server srv#) (.getConnectors) (first) (.getLocalPort))] (try ~@body (finally (jetty/shutdown srv#))))) (defmacro with-test-webserver "Constructs and starts an embedded Jetty on a random port, and evaluates `body` inside a try/finally block that takes care of tearing down the webserver. `app` - The ring application the webserver should serve `port-var` - Inside of `body`, the variable named `port-var` contains the port number the webserver is listening on Example: (let [app (constantly {:status 200 :headers {} :body \"OK\"})] (with-test-webserver app port ;; Hit the embedded webserver (http-client/get (format \"http://localhost:%s\" port))))" [app port-var & body] `(with-test-webserver-and-config ~app ~port-var {} ~@body)) (defn get-jetty-mbean-object-names "Queries the JVM MBean Registry and returns the ObjectNames of all of the Jetty MBean container objects. For the purposes of tk-j9, there should be one ObjectName per Jetty Server instance, *if* the jmx-enabled setting is set to 'true'." [] (jmx/mbean-names "org.eclipse.jetty.jmx:type=mbeancontainer,*")) (defn assert-clean-shutdown "A test fixture that can be used to ensure that all of the Jetty instances have been cleaned up properly by the tests in a particular test namespace." [f] (f) ;; This sucks, because if this assertion fails, it will not give any clue as to ;; which test caused it to fail beyond just the test namespace. However, I tried ;; several things (such as throwing an exception here rather than having an assertion), ;; and nothing gave any better debugging info because the metadata about which ;; test we're running and the call stack for the test function itself are simply ;; not available from inside a fixture. So I decided that even those these aren't ;; super fun to debug, it was better than any other option in terms of enforcing ;; that the tests clean up after themselves properly. (is (= 0 (count (get-jetty-mbean-object-names))))) webserver/000077500000000000000000000000001527232126200344205ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/testutilscommon.clj000066400000000000000000000050151527232126200364030ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/clj/puppetlabs/trapperkeeper/testutils/webserver(ns puppetlabs.trapperkeeper.testutils.webserver.common (:require [puppetlabs.http.client.sync :as http-client]) (:import (appender TestListAppender) (com.puppetlabs.ssl_utils SSLUtils))) (defn http-get ([url] (http-get url {:as :text})) ([url options] (http-client/get url options))) (defn http-put [url options] (http-client/put url options)) (def jetty-plaintext-config {:webserver {:port 8080}}) (def jetty-plaintext-large-request-config {:webserver {:port 8080 :request-header-max-size 16192}}) (def jetty-multiserver-plaintext-config {:webserver {:foo {:port 8085} :bar {:port 8080 :default-server true}}}) (defn jetty-ssl-jks-config [] {:webserver {:port 8080 :ssl-host "0.0.0.0" :ssl-port 8081 :keystore (str "./dev-resources/config/jetty/ssl/keystore." (if (SSLUtils/isFIPS) "bcfks" "jks")) :truststore (str "./dev-resources/config/jetty/ssl/truststore." (if (SSLUtils/isFIPS) "bcfks" "jks")) :key-password "Kq8lG9LkISky9cDIYysiadxRx" :trust-password "Kq8lG9LkISky9cDIYysiadxRx"}}) (def jetty-ssl-pem-config {:webserver {:port 8080 :ssl-host "0.0.0.0" :ssl-port 8081 :ssl-cert "./dev-resources/config/jetty/ssl/certs/localhost.pem" :ssl-key "./dev-resources/config/jetty/ssl/private_keys/localhost.pem" :ssl-ca-cert "./dev-resources/config/jetty/ssl/certs/ca.pem"}}) (def jetty-ssl-client-need-config (assoc-in jetty-ssl-pem-config [:webserver :client-auth] "need")) (def jetty-ssl-client-want-config (assoc-in jetty-ssl-pem-config [:webserver :client-auth] "want")) (def jetty-ssl-client-none-config (assoc-in jetty-ssl-pem-config [:webserver :client-auth] "none")) (def default-options-for-https-client {:ssl-cert "./dev-resources/config/jetty/ssl/certs/localhost.pem" :ssl-key "./dev-resources/config/jetty/ssl/private_keys/localhost.pem" :ssl-ca-cert "./dev-resources/config/jetty/ssl/certs/ca.pem" :as :text}) (def absurdly-large-cookie (apply str (repeat 8192 "a"))) (def dev-resources-dir "./dev-resources/") (defmacro with-test-access-logging "Executes a test block and clears any messages saved to the TestListAppender before and afterwards." [& body] `(do (.clear (TestListAppender/list)) (try (do ~@body) (finally (.clear (TestListAppender/list)))))) OpenVoxProject-trapperkeeper-webserver-8a905f4/test/java/000077500000000000000000000000001527232126200235545ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/java/appender/000077500000000000000000000000001527232126200253525ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/java/appender/TestListAppender.java000066400000000000000000000017131527232126200314510ustar00rootroot00000000000000package appender; import ch.qos.logback.access.common.PatternLayout; import ch.qos.logback.access.common.PatternLayoutEncoder; import ch.qos.logback.access.common.spi.IAccessEvent; import ch.qos.logback.core.AppenderBase; import ch.qos.logback.core.encoder.Encoder; import java.util.ArrayList; import java.util.List; /** * Created by Preben Ingvaldsen on 9/17/14. */ public class TestListAppender extends AppenderBase { public static List list = new ArrayList(); protected PatternLayoutEncoder encoder; @Override public void start() { if (encoder != null) { encoder.start(); } super.start(); } protected void append(E e) { PatternLayout layout = (PatternLayout)encoder.getLayout(); String s = layout.doLayout((IAccessEvent)e); list.add(s); } public void setEncoder(Encoder encoder) { this.encoder = (PatternLayoutEncoder)encoder; } } OpenVoxProject-trapperkeeper-webserver-8a905f4/test/java/servlet/000077500000000000000000000000001527232126200252405ustar00rootroot00000000000000OpenVoxProject-trapperkeeper-webserver-8a905f4/test/java/servlet/SimpleServlet.java000066400000000000000000000030741527232126200307050ustar00rootroot00000000000000package servlet; import java.io.IOException; import jakarta.servlet.ServletOutputStream; import jakarta.servlet.http.HttpServlet; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; public class SimpleServlet extends HttpServlet { private String body; private String contentType; private Boolean bodyAsOutputStream; public SimpleServlet(String body, String contentType, Boolean bodyAsOutputStream) { this.body = body; this.contentType = contentType; this.bodyAsOutputStream = bodyAsOutputStream; } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { response.setContentType(this.contentType); response.setStatus(HttpServletResponse.SC_OK); String pathInfo = request.getPathInfo(); if (pathInfo != null && pathInfo.length() > 1 && pathInfo.charAt(0) == '/') { if (this.bodyAsOutputStream) { byte[] bytes = body.getBytes("UTF8"); response.setContentLength(bytes.length); try (ServletOutputStream out = response.getOutputStream()) { out.write(bytes); } } else { response.getWriter().print(this.getInitParameter(pathInfo.substring(1))); } } else { if (this.bodyAsOutputStream) { byte[] bytes = body.getBytes("UTF8"); response.setContentLength(bytes.length); try (ServletOutputStream out =response.getOutputStream()) { out.write(bytes); } } else { response.getWriter().print(body); } } } }