pax_global_header00006660000000000000000000000064136605626530014526gustar00rootroot0000000000000052 comment=dff547d956eae4e9aa23bc1a083815bba44ff089 trapperkeeper-webserver-jetty9-4.1.0/000077500000000000000000000000001366056265300176315ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/.gitignore000066400000000000000000000002751366056265300216250ustar00rootroot00000000000000.lein-failures .lein-repl-history target/ checkouts/ pom.xml .nrepl-port /resources/locales.clj /resources/puppetlabs/trapperkeeper_webserver_jetty9/Messages*.class /dev-resources/i18n/bin trapperkeeper-webserver-jetty9-4.1.0/.travis.yml000066400000000000000000000011671366056265300217470ustar00rootroot00000000000000language: clojure lein: 2.9.1 jobs: include: - stage: jdk8 script: lein with-profile dev test jdk: openjdk8 # this env var isn't actually used, but helps with readability # in the Travis CI web page env: - FIPS=false - # still jdk8 script: lein with-profile fips test jdk: openjdk8 env: - FIPS=true - stage: jdk11 script: lein with-profile dev test jdk: openjdk11 env: - FIPS=false - # still jdk11 script: lein with-profile fips test jdk: openjdk11 env: - FIPS=true notifications: email: false trapperkeeper-webserver-jetty9-4.1.0/CHANGELOG.md000066400000000000000000000521741366056265300214530ustar00rootroot00000000000000## 4.1.0 Update jetty version to 9.4.28. This is a maintenance update. ## 4.0.3 Fix ambiguous type inference when running under Java 11 ## 4.0.2 Further FIPS updates and cleanup ## 4.0.1 Add a FIPS profile and remove SSLv3 support. ## 4.0.0 Further restrict cipher-suites and protocols to current best practices. See documentation for configuring Jetty for additional details. ## 3.0.3 This was released but had no code changes ## 3.0.2 Suppress warning about empty contextPath ## 3.0.1 This is a bug fix release With this release we no longer fail to start if so-linger-seconds is set, only warn the user that the seeting will be ignored. This should allow easier upgrade paths. ## 3.0.0 This is a feature release with backwards breaking changes. * Java 11 support. This library should now be runnable and compilable on Java 11. * Jetty version bump from v9.4.11 to v9.4.18. This version bump resolves many issues with Jetty and enables the above Java 11 support. It also breaks several existing configurations. * `so-linger-seconds` option removed. Jetty maintainers realized this option had undefined behavior and removed the underlying option. * `IOException` thrown when failure to bind to port. Previously, this library tested that `BindException` was thrown and treated it as an API. This was invalid from the Jetty maintainers standpoint (they only test that the more general `IOException` is thrown). * Default Cipher Suite refresh. Only three of the existing default ciphers were still considered by Jetty to be secure enough not to cause warnings on startup. These three cipher suites remain and many additional modern cipher suites have been added. ## 2.4.1 * [PCP-862](https://tickets.puppetlabs.com/browse/PCP-862) Only disconnect if the session has not already been closed. ## 2.4.0 * [PCP-862](https://tickets.puppetlabs.com/browse/PCP-862) Add disconnect function to allow disconnecting from websocket connections rather than closing them * (maint) Renew expired SSL certificates This renews expired SSL certificates `certs/ca.pem`, `certs/localhost.pem`, and `certs/localhost.p12`, which were causing tests to fail unexpectedly. ## 2.3.1 * [TK-473](https://tickets.puppetlabs.com/browse/TK-473) Stop reporting jetty version in responses ## 2.3.0 This is a feature release. * [TK-470](https://tickets.puppetlabs.com/browse/TK-470) Add MDC support This release adds the ability to use the MDC (Mapped Diagnostic Context) to save per thread diagnostic information about requests. That information may then be output in request logs as desired. For more information see https://logback.qos.ch/manual/mdc.html. * (maint) Update version dependencies This moves us to using clj-parent 2.x (adds improved support for Java 11 and Clojure 1.9) ## 2.2.0 This is a dependency update release that should be transparent to users but may have upgrade risks. * [SERVER-2213](https://tickets.puppetlabs.com/browse/SERVER-2118) Upgrade Jetty to latest This upgrades from Jetty 9.4.4.v20170414 to Jetty 9.4.11.v20180605. The only thing of note noticed in testing is that minimum threads allocated per connection has changed, now scaling up and down with the size of the server's threadpool. This change has not been noticed to cause issue with any default setup, though with a version bump of this size there may be yet uncaught regressions. ## 2.1.2 This is a bug fix release. * [SERVER-2118](https://tickets.puppetlabs.com/browse/SERVER-2118) Enable gzipping post request responses. A jetty update requiring HTTP methods to be whitelisted before their responses could be gzipped broke gzipping of POST request responses. This patch updates our jetty configuration to also allow gzipping of POST requests, instead of just GET requests. ## 2.1.1 This is a bug fix release, but contains important upgrade information. * [SERVER-1597](https://tickets.puppetlabs.com/browse/SERVER-1597) Enforce disallowed content re-negotiation. Previously, Jetty would allow content negotiation despite being documented as defaulting to disallow. This patch explicitly disallows as a default and provides users the means to allow renegotiation by using the `webserver.allow-renegotiation` key. Also, a special thanks to @EdwardBetts for the documentation fix! ## 2.1.0 This is a feature release. * [TK-451](https://tickets.puppetlabs.com/browse/TK-451) Support runtime refresh of Jetty CRL via puppetlabs/trapperkeeper-filesystem-watcher. Changes to CRL will result in Jetty reloading the CRL without a server reload or restart. ## 2.0.1 The 2.0.0 release was mistakenly for a Java 7 runtime even though the underlying Jetty libraries were built for Java 8 runtime. The code for this release is built for a Java 8 runtime instead. ## 2.0.0 This is a major release * [TK-369](https://tickets.puppetlabs.com/browse/TK-369) Move Jetty dependency to 9.4.4. Notably, this change drops Java 7 support as Jetty 9.3 and higher only support Java 8 and higher. No public APIs have changed in this release. * The behavior of normalize-uri-path has changed slightly due to changes in Jetty's URIUtil decodePath method. Specifically, overlong encodings (which are considered invalid UTF-8) change their decoded value (but are still not traversable), and semicolons no longer terminate URI processing, but only when ; is followed at some point by another path segment beginning with /. For example, "/foo/bar;bar=chocolate/baz;baz=bim" now decodes to "/foo/bar/baz" while before it decoded to "/foo/bar". If the request has invalid % encoded UTF-8 characters, the path will be decoded as an ISO-8859-1 encoded string. (https://github.com/eclipse/jetty.project/commit/7f62f2600b943b9aed0e4771891939bf61372c5a) * [TK-373](https://tickets.puppetlabs.com/browse/TK-373) Enable Diffie Hellman cipher suites. DHE cipher suites were previously disabled due to bugs with DH ciphers on Oracle JDK 7. * [TK-374](https://tickets.puppetlabs.com/browse/TK-374) Remove obsolete SSL ciphers. ## 1.8.0 This is a feature release. * [TK-149](https://tickets.puppet.com/browse/TK-149) Support runtime refresh of Jetty CRL via puppetlabs/trapperkeeper-filesystem-watcher - changes to CRL will be result in Jetty reloading the CRL without a service reload or restart. ## 1.7.0 This is a feature and bugfix release. * [SERVER-1695](https://tickets.puppetlabs.com/browse/SERVER-1695) Add an optional `request-body-max-size` setting for restricting the maximum `Content-Length` allowed for requests. * [TK-429](https://tickets.puppetlabs.com/browse/TK-429) Fix for the ability to gzip-encode response bodies when an access log is configured. ## 1.6.0 This is a "feature" release. * Added a new function `request-path` to the WebsocketProtocol * [TK-410](https://tickets.puppetlabs.com/browse/TK-410) Add the i18n library as a dependency and use it to externalize strings. ## 1.5.10 This is a maintenance release. * Remove unneeded logback-access dependency ## 1.5.9 This is a maintenance release. * Upgrade ring-servlet and related dependencies to 1.4.0 ## 1.5.8 This is a maintenance release. * Upgrade java.jmx dependency to 0.3.1 ## 1.5.7 This is a bugfix release. * [TK-372](https://tickets.puppetlabs.com/browse/TK-372) Fix a memory leak that occurred when a SIGHUP was used to restart services and at least one webserver has Jetty's JMX metrics enabled. ## 1.5.6 This is a security release. * [TK-343](https://tickets.puppetlabs.com/browse/TK-343) Support a new option for handler registrations, `normalize-request-uri`, which can be used to request that the URI path component is sanitized before the handler is invoked for a request and that `.getRequestURI` calls made by the handler return a path that has been percent-decoded. ## 1.5.5 This is a bugfix and maintenance release. * [TK-333](https://tickets.puppetlabs.com/browse/TK-333) Tolerate multiple calls to `stop` by ensuring that the server shuts down and cleans up mbeans in an idempotent way. * Upgrade Trapperkeeper dependency to 1.3.1 * Upgrade Clojure dependency to 1.7.0 ## 1.5.4 This is a bugfix release. * [TK-338](https://tickets.puppetlabs.com/browse/TK-338) Handle the `TimeoutException` that Jetty throws if its `stopTimeout` is reached before it can gracefully complete all of the open requests. Ensures that the server will be restarted during a HUP even if the timeout occurs. ## 1.5.3 This version number was burned due to an error during the release/deploy process. ## 1.5.2 This is a maintenance release. * Make `org.clojure/java.jmx` a top-level dependency so that it can be pulled in automatically via a transitive dependency by consumers of the testutils jar. ## 1.5.1 This is a bugfix release. * [TK-301](https://tickets.puppetlabs.com/TK-301) Fix a memory leak related to Jetty's JMX metrics; this leak is only relevant if using the recent HUP support released in Trapperkeeper 1.3.0. ## 1.5.0 This is a "feature" release. * Added new function `get-server` to web routing service. ## 1.4.1 This is a bugfix release. * [TK-270](https://tickets.puppetlabs.com/TK-270) Fix a bug that prevented the use of 1-arity WebsocketProtocol/close!. ## 1.4.0 This is a feature and maintenance release. * [TK-247](https://tickets.puppetlabs.com/TK-247) Added tests for Path Traversal Attacks. * Add experimental support for websockets via the `add-websockets-handler` function in the WebserverService and WebroutingService and corresponding client protocol WebsocketProtocol. * Updated ssl-utils dependency to 0.8.1 ## 1.3.1 This is a maintenance release. * [TK-195](https://tickets.puppetlabs.com/browse/TK-195) Update prismatic dependencies to the latest versions ## 1.3.0 This is a "feature" and security release. * [TK-178](https://tickets.puppetlabs.com/browse/TK-178) Upgraded Jetty version dependency to v9.2.10. Jetty v9.2.10 includes changes made in the Jetty v9.2.9 release to address a critical security vulnerability with data potentially being leaked across requests. See https://dev.eclipse.org/mhonarc/lists/jetty-announce/msg00074.html for more information. For a rollup of changes included in the Jetty v9.2.10 release, see https://github.com/eclipse/jetty.project/blob/jetty-9.2.10.v20150310/VERSION.txt. * [TK-168](https://tickets.puppetlabs.com/browse/TK-168) Default values for several settings will now derive from the underlying defaults that Jetty would use. This effectively changes the defaults for the following settings: - `shutdown-timeout-seconds` in `webserver` section - 60 seconds -> 30 seconds - `:idle-timeout` for `add-proxy-route` - 60 seconds -> 30 seconds * [TK-148](https://tickets.puppetlabs.com/browse/TK-148) Several related changes: - Default for `max-threads` in `webserver` section changed from 100 to 200. - Exposed new settings for configuring the number of `acceptor-threads` and `selector-threads` that a Jetty webserver will use. - Removed work which would automatically bump the server's `max-threads` up to the minimum needed for the server to boot for the case that `max-threads` had not been configured but the server's minimum needed threads had exceeded the default `max-threads`. The original work which enabled the automatic bump had been done in [TK-130](https://tickets.puppetlabs.com/browse/TK-130). ## 1.2.0 This is a feature release. * Upgrade to version 9.2.8 of upstream Jetty. We were previously at v9.1.0, which was over a year old. The newer version contains some performance improvements and bug fixes for potential networking issues. * [TK-140](https://tickets.puppetlabs.com/browse/TK-140) Expose new `so-linger-seconds` setting, which can be used to adjust the TCP SO_LINGER time. * [TK-144](https://tickets.puppetlabs.com/browse/TK-144) Expose new `post-config-script` setting; this is for advanced / edge-case configuration needs. If you need to modify a Jetty setting that we don't expose in our own config, you can provide a snippet of Java code to access the Jetty Server object directly and modify additional settings. * [TK-133](https://tickets.puppetlabs.com/browse/TK-133) Support comma-delimited strings for the config value for `ssl-protocols` and `cipher-suites`. This allows these settings to be used with older config file formats, such as ini. * [TK-151](https://tickets.puppetlabs.com/browse/TK-151) Expose new `idle-timeout-milliseconds` setting, which can be used to tell Jetty to forcefully close a client connection if it is idle for a specified amount of time. ## 1.1.1 * [TK-82](https://tickets.puppetlabs.com/browse/TK-82) Add configuration option to control maximum number of open HTTP connections that Jetty will maintain. * Upgrade trapperkeeper dependency to 1.0.1. * Upgrade jvm-ssl-utils (previously known as jvm-certificate-authority) dependency to 0.7.0. ## 1.1.0 * [TK-130](https://tickets.puppetlabs.com/browse/TK-130) The default value for Jetty's maximum threadpool size is now calculated to ensure it can start up on a box with a large number of cores. ## 1.0.1 * This release adds an additional configuration option to `add-proxy-route` ([TK-110](https://tickets.puppetlabs.com/browse/TK-110)). ## 1.0.0 * Promoting previous version to 1.0.0 so that we can begin to be more deliberate about adhering to semver in the future. ## 0.9.0 This is a security release. * [TK-96](https://tickets.puppetlabs.com/browse/TK-96): Define a default set of SSL protocols that the server should allow (TLSv1, TLSv1.1, TLSv1.2) and use them if the user doesn't explicitly set the `ssl-protocols` setting. ## 0.8.1 This is a minor bugfix release. * Fix an issue wherein the default graceful shutdown timeout was not being set to 60 seconds. ## 0.8.0 * Adds a new option, `:redirect-if-no-trailing-slash`, that determines whether or not a 302 response will be returned when making requests to endpoints with registered handlers without a trailing slash on the end. * By default, requests will now route through to a handler when no trailing slash is present on the request URL rather than returning a 302 response (which was the behavior in previous versions). * Adds graceful shutdown support and a new option to the webserver config, `shutdown-timeout-seconds`, that allows users to set the stop timeout of the Jetty server. ## 0.7.7 This is a minor feature and bugfix release. * Improves various error messages thrown by the Webrouting and Webserver services. * Changes the data structure output by the `get-registered-endpoints` and `log-registered-endpoints` functions. Now, a map will be output where each key is an endpoint, with its value being an array containing information on every handler registered at that endpoint. * Adds a new option to the webserver configuration, `access-log-config`, that allows configuration of request logging. * [TK-84](https://tickets.puppetlabs.com/browse/TK-84) Query parameters were not being decoded when the URI was being rewritten in the reified ProxyServlet class, meaning they would get double encoded. * Adds a new option to `add-proxy-route`, `failure-callback-fn`, which allows customization of HTTP Error Responses. ## 0.7.6 This is a dead release. ## 0.7.5 This is a minor feature release. * [TK-75](https://tickets.puppetlabs.com/browse/TK-75) Adds a new option `gzip-enable` that can be used to enable/disable support for gzipping responses to requests that include an appropriate `Accept-Encoding` header. ## 0.7.4 This is a minor feature release. * Adds a new option to both the `static-content` configuration setting in the webserver config and to the add-context-handler service function that allows symlinks to be followed when serving static content. ## 0.7.3 This is a minor feature release. * Adds a new, optional `static-content` configuration setting to the webserver config. This setting allows you to serve files on disk or resources in a jar as static assets at a given URL prefix, all via configuration. ## 0.7.2 This is a minor, backward-compatible feature and bugfix release. * [TK-58](https://tickets.puppetlabs.com/browse/TK-58): `default-server` support did not work for some functions, such as `get-registered-endpoints`. * Add support for SSL certificate chains, and new setting `ssl-cert-chain` * Upgrade to Trapperkeeper 0.5.1 ## 0.7.1 * [TK-53](https://tickets.puppetlabs.com/browse/TK-53): Add a `get-route` function to web routing service. * [TK-33](https://tickets.puppetlabs.com/browse/TK-33): Add support for configuring proxy routes to automatically follow redirects from the remote server. * In proxy configuration, add support for a callback function that can rewrite the URI before the request is proxied. * [TK-45](https://tickets.puppetlabs.com/browse/TK-45): Add support for strings in addition to keywords when specifying the URI scheme for proxy requests. ## 0.7.0 * [TK-50](https://tickets.puppetlabs.com/browse/TK-50): Changes to "default" server handling in a multi-server configuration: * It is no longer required to specify a default server. If a service function is called without specifying a `server-id` when there are multiple servers configured, an error will be thrown. * It is no longer required that the default server be named `default`; instead it is configured by specifying `default-server: true` in the configuration for the given server. * [TK-51](https://tickets.puppetlabs.com/browse/TK-51): Added the ability to the specify `server-id` in the `WebroutingService` configuration, instead of forcing it to be done in code. * Minor bug fixes and improvements: * [TK-48](https://tickets.puppetlabs.com/browse/TK-48), [TK-44](https://tickets.puppetlabs.com/browse/TK-44) ## 0.6.1 * Add configuration option `request-header-max-size` * Increase default buffer sizes for request and response * Update test dependencies to latest version of puppetlabs/http-client (0.2.1) ## 0.6.0 * The `WebserverService` can now run multiple Jetty servers, on different ports. * Added a new `WebroutingService` to provide a centralized, configuration-based way to configure all of the URL paths at which services will register web applications (Ring handlers, Servlets, etc.) * Added JMX reporting to the `jetty9-service` * Added `get-registered-endpoints` and `log-registered-endpoints` functions to the `WebserverService` * Minor bug fixes and improvements: * [TK-21](https://tickets.puppetlabs.com/browse/TK-21), [TK-22](https://tickets.puppetlabs.com/browse/TK-22), [TK-31](https://tickets.puppetlabs.com/browse/TK-31), [TK-43](https://tickets.puppetlabs.com/browse/TK-43) * Upgraded trapperkeeper dependency to version 0.4.3 * Upgraded kitchensink dependency to version 0.7.2 ## 0.5.2 * Update trapperkeeper dependency to version 0.4.2. * Update kitchensink dependency to version 0.7.1. * Update certificate-authority dependency to 0.1.5. * Update http-client dev dependency to 0.1.7. * Stop is now called on the Jetty Server instance if an error occurs in Jetty code while the server is starting up. This allows the process running Trapperkeeper to shut down properly after such an error has occurred. * Validation of the webserver configuration is now done via the use of Prismatic Schema. * A new webserver option, `ssl-crl-path`, can be used to configure a Certificate Revocation List that Jetty would use to validate client certificates for incoming SSL connections. ## 0.5.1 * Upgrade trapperkeeper dependency to version 0.3.12 * Upgrade kitchensink dependency to version 0.7.0 * Replace clj-http dependency with [puppetlabs/http-client](https://github.com/puppetlabs/clj-http-client) * Update test/example configuration files to use HOCON instead of .ini files ## 0.5.0 * Added new function `override-webserver-settings!`, which allows another service to provide overridden values for the webserver configuration. * Update to latest version of puppetlabs/kitchensink * Use puppetlabs/certificate-authority for all SSL-related tasks ## 0.4.0 * Added new function `add-proxy-route`, which supports configuring the server to work as a reverse proxy for certain routes ## 0.3.5 * Added a new service function, `add-context-handler`, which supports registering a context handler for static content, with optional support for context listeners via the `javax.servlet.ServletContextListener` interface. ## 0.3.4 * Added support for registering WAR files via the `add-war-handler` service function. * Moved server creation from the `init` life cycle to the `start` life cycles. ## 0.3.3 * Fix bug where even if no http `port` was specified in the webserver config, the Jetty webserver was still opening an http binding on port 8080. An http port binding will now be opened only if a `port` is specified in the config file. * A config file can now optionally include a `client-auth` webserver setting. The setting specifies how the server validates the client certificate during the setup of an SSL connection. The default behavior if the setting is not specified is the same as with prior releases; the server will require that the SSL client provide a certificate and that the certificate be valid. For more information, refer to the [jetty-config.md] (doc/jetty-config.md) document. trapperkeeper-webserver-jetty9-4.1.0/CODEOWNERS000066400000000000000000000002621366056265300212240ustar00rootroot00000000000000# This will cause the puppetserver-maintainers group to be assigned # review of any opened PRs against the branches containing this file. * @puppetlabs/puppetserver-maintainers trapperkeeper-webserver-jetty9-4.1.0/CONTRIBUTING.md000066400000000000000000000010171366056265300220610ustar00rootroot00000000000000# How to contribute Third-party patches are essential for keeping puppet open-source projects great. We want to keep it as easy as possible to contribute changes that allow you to get the most out of our projects. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. For more info, see our canonical guide to contributing: [https://github.com/puppetlabs/puppet/blob/master/CONTRIBUTING.md](https://github.com/puppetlabs/puppet/blob/master/CONTRIBUTING.md) trapperkeeper-webserver-jetty9-4.1.0/LICENSE000066400000000000000000000260751366056265300206500ustar00rootroot00000000000000Apache 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. trapperkeeper-webserver-jetty9-4.1.0/Makefile000066400000000000000000000000441366056265300212670ustar00rootroot00000000000000include dev-resources/Makefile.i18n trapperkeeper-webserver-jetty9-4.1.0/README.md000066400000000000000000001044441366056265300211170ustar00rootroot00000000000000[![Build Status](https://travis-ci.org/puppetlabs/trapperkeeper-webserver-jetty9.png?branch=master)](https://travis-ci.org/puppetlabs/trapperkeeper-webserver-jetty9) ## Trapperkeeper Webserver Service This project provides a webserver service for use with the [trapperkeeper service framework](https://github.com/puppetlabs/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/puppetlabs/trapperkeeper-webserver-jetty9/latest-version.svg)](http://clojars.org/puppetlabs/trapperkeeper-webserver-jetty9) Then add the webserver service to your [`bootstrap.cfg`](https://github.com/puppetlabs/trapperkeeper#bootstrapping) file, via: puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-service Note that this implementation of the `:WebserverService` interface is based on Jetty 9, which contains performance improvements over previous versions of Jetty that may be significant depending on your application. This service requires JRE 1.7 or greater; however, the interface is intended to be agnostic to the underlying web server implementation. We also provide a [Jetty 7 version of the service](https://github.com/puppetlabs/trapperkeeper-webserver-jetty7), 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/puppetlabs/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. 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` NOTE: Websockets support is currently an experimental feature; the API for websockets support may be subject to minor changes in a future release. `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.experimental.websocket.client` 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.experimental.websockets.client :as ws-client])) (def echo-handlers {:on-text (fn [ws text] (ws-client/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). * `:failure-callback-fn`: optional; a function to manipulate the response object in case of failure. The function must accept four arguments, `[req resp proxy-resp failure]`. For more information, see [below](#failure-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. #####`:failure-callback-fn` This option lets you provide a function to manipulate the response object in case of failure. It must take four arguments, `[req resp proxy-resp failure]`, where `req` is the original [`HttpServletRequest`](http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletRequest.html), `resp` is an [`HttpServletResponse`](http://docs.oracle.com/javaee/6/api/javax/servlet/http/HttpServletResponse.html), `proxy-req` a [`Response`](http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/client/api/Response.html) and `failure` is a [`Throwable`](http://docs.oracle.com/javase/7/docs/api/java/lang/Throwable.html) explaining the cause of the problem. `resp` may be modified, the function does not return any value. An example with an on-failure function: ```clj (defservice foo-service [[:WebserverService add-proxy-route]] (init [this context] (add-proxy-route {:host "localhost" :port 10000 :path "/bar"} "/foo" {:failure-callback-fn (fn [req resp proxy-resp failure] (.println (.getWriter resp) (str "Proxying failed: " (.getMessage failure))))}) context)) ``` In this example, in case of proxying failure the response body will be augmented by an error message explaining what the cause of the problem was. #### `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 Jetty9 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/puppetlabs/trapperkeeper-webserver-jetty9/blob/master/src/puppetlabs/trapperkeeper/services/webserver/jetty9_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 We use the [Trapperkeeper project on JIRA](https://tickets.puppetlabs.com/browse/TK) for tickets on the Trapperkeeper Webserver Service, although Github issues are welcome too. trapperkeeper-webserver-jetty9-4.1.0/dev-resources/000077500000000000000000000000001366056265300224175ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/Makefile.i18n000066400000000000000000000141471366056265300246440ustar00rootroot00000000000000# -*- 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_jetty9 # The name of the POT file into which the gettext code strings (msgid) will be placed POT_NAME=trapperkeeper-webserver-jetty9.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 trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/000077500000000000000000000000001366056265300236645ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/000077500000000000000000000000001366056265300250235ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/000077500000000000000000000000001366056265300256245ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/000077500000000000000000000000001366056265300267445ustar00rootroot00000000000000ca-master-intermediate-and-root.pem000066400000000000000000000051211366056265300354340ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/ca-master-intermediate.pem000066400000000000000000000025731366056265300340020ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/ca-root.pem000066400000000000000000000023251366056265300310150ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/ca.pem000066400000000000000000000034151366056265300300350ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/localhost-compromised.pem000066400000000000000000000037611366056265300337650ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/localhost.p12000066400000000000000000000122451366056265300312640ustar00rootroot0000000000000000g *H XT0P0  *H  x0 t0 m *H 0 *H  0\(w H @B\k9!R Rҫ8im͖C8qQŶgbS~esH\!gkL'hQ}dзm:<@xe'Ĕ$.k 6ʆE 12*_{у7p8ׁ-8muzVGҨJ9?-Vsfܓ{v;T5#jci52 ! %xI[^cG_4xcz\"k;%3$.S$Gy/D.׆l 8Faz ip+F%3U'7lsTa~)SL 7af@U%*O>K}1r2D)Pzz[U*zɃ$&G*깩R Uϴ9sG#L6q щ6 1kkқ3x"՞hc闭q2Цp^Wo'm.*c(z4͟FV`DJbXP]jf(C0w;b%;c1*Uo9Xq6&GAYHDrΧyu1qJ >o50GAi_b7ОĒh6M*YB9]\̐ }M$. 6\Y.{f*.aĊ7 _F<N]@Ě0});< TUS.>кMcK<#S")J$M K*DR&,tK--i!`cP ?tDwH[gmQUG#kV_8V0-Bxf1Oog*w˲Eӹ{ Or5Z?rQrЖqKF\5jD燻(\t'>-e[i8$Oߞxoţu+8-~#t b~`_k.}Ap\&q8MP9|~\ss%nH7]o-:N}$,4e &>~9/l^+ޙxWG"ꫵ 8xZo~}xOͳ2`SL= RnpΎؒeaʛȺty;5U9 XgV9a(U~TuNfx v{µS.$:ǿl&.@%(:lqWJ =&M@ =ZE;xT/lf/Fqg)=Q*j2ɋ2OJEJ|a٭ce+ګXL*^{S춦0  *H   0 0  *H   n0 j0 *H  0P t] HfY68syըO9 --_Pd{rGG0;&UHEXkO׸#ӪLq[ѼsO13=+3輨՗՗qCȺ{jjoHWr OYS 7A-a8Ygb+ߌ麪6ӗ >8;!|?bVqSaR؅@NSx(&WqAJ]׷ ҧ3ATX+̼)w&,^yzě 0@KO o uQJ L-ႅ!&.<,sHWgJrNǸT`?tnSVʗvk*5]8]j5C,EasM394$d!9TʞD8k0CvГB }0lNŞW= wo 5+4Xx{"5nEsN. ғ3$_-W`jtUmMo',f~4y߽ o)γBc/*pyf<@PԘ Khơ@w}غN7PSQk<`X"O4<9`,DTqN|Z`fY*paY"u&-Z]#V-sh"L8]g_@cEuNbUQO}vWEvɸaM5QY^H.J= lhN9~!PtΚX\ V2CL7p;&+j1p;p8~|S,NWeEz)wM"E*JNu#ͭI?ID[@9]AIP1Fβ7f^݂Aɲ w.A֖ZAUETtc)cՂ?y0SLo])בuTh6.6:$GFk3 9C OV('10":]T|u\1 LlfoxK. P/3n ?2\~y_mrzN((axej?s6E3iU,RADJV~6׬cZD U`y}m$dp@.]zEvA$ c+Y A'iC#YMmU])٘_ƌqOȪnv6/ heKz\ #N.FvEh8|&NA{EEcm•%qbMO*ۘ>QWVuָi|+M4֤ˑ(YI1KBR ţv~cP- U ]8$w1\.2_F!NЖ &iB=b\˿ȟ}s| / Btч`cma%4{mϦ)qCY_~ze6jk?k@\u !4c;4ZĸQ9` *s*@reEâ2]f l+M7 2ddsaqg/VH e3̚ziGB!= 87II\\Sd"^ӿ9M(*g0e&ZiUӒd`,b-du{E<+B&2W:)`1# !}sʭ-`1T?=6a=^4Hpc6 L%kA!.ҩ61TPhQ8 '&gWa784Y @:__\QF}^Lґ5)$)$[@ {ڈU9?=D۵ؚT.";cvxּw]2 .ncĂ`݂(K +E}j}8>48Vn3WW4L TrUEܰaН s6TԷ,YAoH$c- 1~'7A$Ưafʮg(x'k#{F@C010!0 +TJ/>b+"_i@%iHYtrapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/localhost.pem000066400000000000000000000032131366056265300314360ustar00rootroot00000000000000-----BEGIN CERTIFICATE----- MIIEpzCCAo8CAQIwDQYJKoZIhvcNAQELBQAwHzEdMBsGA1UEAwwUUHVwcGV0IENB OiBsb2NhbGhvc3QwHhcNMTkwMjI1MTUxNzQwWhcNMjkwMjIyMTUxNzQwWjAUMRIw EAYDVQQDDAlsb2NhbGhvc3QwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoIC AQC85+MXGxoUl+uX4EiKPjQeBDmF/sycWx2pr/oW0JIQMah8VErMww/OvrPWbDfH L6QyEXsdf0n5DUSoYFVBxolGG6JfvUS6YKXR2CyQmNEtJDsgVIFqhHEKwLVQ2KcG jQuajJ3omZHDb0O+KZ7hTmtP2826S8jo2ChEKtwVyt9shiyx7Hm/zyF9aG6nLmIk esiO0t8CvYSc0qOgUT0s9HDWTaZ121v8i0bR27YQbc04nzNjFto7Vrhb4DltZcvb 8cExwqyb+SsTLm1Q66gMfkZpjrJ99uwDzt6+jVK9gs1dbxvAjKiwKbHupnSqQmeV DS5uHcAlHts1gENENhG2vPDuPNGx/JP7fDVBl5VrduQfAVBPK5JWNI8EsL/A8o3W tJqHqMYDDGW/qID402Pw7P4doYBc8vw1Lhq7+pMlccx9P6ToNvR3g6FGiiGqowLD fIf6GEyegojigKln24vCWUZohFU3pLJEuXskrD6jwnoHwJH6SJc+BFOBTdANrzkS O3qVuJjYiXAi29Pb+Y6ICvg4X3krHA7K2ICBfHgDy8Oq/YdWpvr16A+r7bSMGQbt eaZwll3Q3ClgTY8fs2FOuPImfVf6hRt9bkyWsNM9fHhT8k3CTfErU56Bmc4yiNgM oxuReqL/0u5p1NyP8L9AeVaunz40rzK7AZWwXSNz2698PwIDAQABMA0GCSqGSIb3 DQEBCwUAA4ICAQAl+Z4XvZSvzncH7IcfhtU+NGDaE5MpB4nxrKjYyohK7/9ru9ln YH65yr2Mt3+tlHGqz1Jxg1pKv/v4v9l77SzGilu4j3zCHxO2Ir9su23ytrtmwWue Qnd9hPUsO1T8xigTZ3TKFkRbvCGmftetl1095/tAufM5loFDk3qOI0Nl5f7Ck8VS zmzohVSB5N9qTFg7YLua/fgGIkCJ7cjLjtU3EZyuNvhi1I/FsWioS8OJ7U+h/2Wx amb3cJvazc2Za9XRL/bMpau1XClOEtpQ8JpG/hbBhOC1fUAnNsmCiNQXlyyGUAdv nS0QBlvlqf/+qBjQ6YEaONzyvHoNLjcsx02ef5u9H21VuJNr8O0G04B1yFHnTExe XgEDolUfoLef+0/aXO8DVomvubWZ9id2Fi0SSDIitMQ9zYsNkhSTswDRJlGs6aVL J2tWn8tnqEezPWsFO+o4ea0RaLIQuxoaM3Ggu3yy4FLT+ME5TaQ1WqXxEJ/TzgF5 rBWfYzhfkQmhooTVDnuuRYG3tuxsQzEaD6cdw8lGXLAXTfPfmjr0pJBTcKrE5BcG 5RcdbN3IBS/HBYSCB6x5AxXMcVAKmFdQFFUMmyCQwfy+CMkA0On7LVv2cecsHE+B 32fBUI8O5aSGdEnNU0x/gv9M/ihRrOj+8Vb67c/B8bBFtoCgDOwDMU7KmA== -----END CERTIFICATE----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/master-with-all-cas.pem000066400000000000000000000077451366056265300332420ustar00rootroot00000000000000-----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.pem000066400000000000000000000054171366056265300346740ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/master-with-root-ca.pem000066400000000000000000000051511366056265300332570ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/master.pem000066400000000000000000000026241366056265300307460ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/certs/unauthorized.pem000066400000000000000000000017351366056265300321760ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/crls/000077500000000000000000000000001366056265300265675ustar00rootroot00000000000000crls_localhost-compromised_revoked.pem000066400000000000000000000017531366056265300362720ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/crls/crls_localhost_revoked.pem000066400000000000000000000017531366056265300340320ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/crls/crls_none_revoked.pem000066400000000000000000000016161366056265300327770ustar00rootroot00000000000000-----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----- trapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/keystore.bcfks000066400000000000000000000224121366056265300305040ustar00rootroot000000000000000%0$I0 *H  00d *H  0W@坷6mr0 :g"+H/%omZyyWj:8 v'Oߚo#`p@ 0 *H  0 `He/0 듂֓#\'ΔNk$0 ҅)M<HDlgO3Pjn&$L`-]sLv ]."˙nw>;hOePv!s3g髖N"W>Ĥ Ϡ +|u{!^tt3x2<94: ~[;"X^3uc#NtNM8JRqjH 5?I[}We hs?5&QKњȳ1a@~w{m NF-! yhoNKǪ@$3c!'WlS e'v ƷwrVڃGOkAP.[R.d\/S$HͱH%rX|OVwMFn2%#w{Qlm7/)pMo餴(c Psyc!_sCpn;7kntSt0& BsԘצ|YqC~>.()#DV22FB9^5K`*ko %V6hܸ=&O7_9NS<-7}Kfi GߠCEWř.LkVd~ؑFP;}M3\dnPR ]I}e멱vm4`{c]\ܛi~J eqy=FEW#A(bmT7pۜTw)p9xʼn9%Ir;g" Q9k9CaѶ26{]5q`!a;\A3Oc<ϫȔ3N|ʙ`y!j |db3qbÊwB- A O.Θ x!saYaRbDO!Z:j?F~BJy< {WEiĐa}RS]zX hopså 69 nķ~=@#_%ڮ̢|2134LsCn($ΈN̅uo`/_% ù#Kkۈvk^gxWo@ `޽'w 8&,_Z!Ua1RI)%kI<&A"-gÅEM&Esk t< V ]k\w WОF3zQVh^E82T~Mf `Ym2ВkiL;.˚=Sa`FWnf>QvU=*җ/{_kڳwzzA #ط7K9Eg=W=U-8SRFBZW>'s` uL2e\tM`POS÷D (G@Н<EѠ_ V iƩR( 6:ѐyܭbsvv%SeM4,gһ+ ~7gʹ%sǴ(CC$w̭i{ v%(վ)b aƽY6,[yS0 Azy;cn^u:F)DIb,vGO7Hp> [x ! ,8X#ћJlxrMlZÚc֗lyUThnb!) mRh`2аo5fxݠ:xu:!,142n hxtFmNb\sݟs[z aEM`ü\TPa^H rL_!)t߫ h(y])oRZe=6BKqrO{^6A8+)MI7 `ؤ,4쪛_gFgzwY~I?rӭF /Qf]ӱreȈ8#+(k*+cAs8& a3άXp9BH_ˍyoyPxM D:nKe8ȀKQY-pe>}ܲts.t:wJ/p9J-5]c]ϩ;˙e70 lhP]_\㫻Fv2F=L[\o|h l*f 6pʂt& ]># L!XYuC%Ht_pkw2)m6 oʄcG⽉y:WfU>|ԑ CaiXG<`Grhjs35  Yzi3q K=0GyРmKk~8٤ÉL)5S]򴥷' r|2K}9@NGBj7G0l{_S \c[x]BO= :WG`EuWcS="Mr4۫00F$] *T׊ЄfsnM|>z2.eQ/ CĨ+sRb L퉁A;0ZoNҬ"NnJAI~pQd_8/nZn1'fMyKsJ;= NvDU7HqeIu&Zf7{C{&7{\/"X1uM ` v{&.C ۹9<ǐpt'Ԅ l)(p \]imvjs8ژ*;-6\)h+~r;_8lT'O =bX|n.Bb8ڇ}F.&i$ί: tpB:QyϤp0\ a3f@|JH׌/|\pjSdׅrFxjvPVP܍w1uRZW=CUoS%SJF8WoVhA+RZ۱;SX9\$aCGSvy.J=Dy/[Fy.r%WEo p#,"܂XD E(N]>SSrj;9~ .[$ \0Ѵae}CI) HpFK2}69417_`P?{ʊd S4<"=/l36(\. U=􂞝3g]ikeཛsi@ *Ͷ FM3XO|P3huv~Ȧ,Jd+t+ίI `Ii]l./`fǑƎh9Vh#x Dۚkݸ?շ+g,DЬvvalR["QY:s(>|r1D6:Y YR pVy }#Ӟ 9YBPot:7>$<`I#i$QP֝"@5x-$ylxGK_4oY 6}y*L H_>mM[p*H'VϞkww>UjzK(\Eg))ֵ; uE-krn D&I?33}WZip6M?ԉGGW5}ongF;E)m˜*YS=+yy Lz=mPWE/lf:UrdM\`}N'SXR.~U.岂U8P"M"X yQPbYHu/]|DOK<?Wܸ@-D~ Io0G_ :dpG+%Fōl(6Ruh^!tTndɛHlFg+#.s@ͽr͔ҍ߄_ Mo"Qu+)DM{@QuN|kZ#a-f+85DA̐iӮ3u~ei6t7 §;w)U-BikW&o쳄zʮKٕN/m{Qؓ9%n0P+Eb8iUtq! 4 w'x$V5fMH9'Ee vkJ>@hKP^X.l=NPXEWf%oO61݁{KTOOMȣk_:MtO`2B \kjw/;^m9u hwoLIUqg;%F= w˻M Ƃu]JB~:XQ?6V`LJ@w.L+<)S8^Do56; 'U /)x?Ug2 !P^4!/W`"hHU|<fgJ;iŮuJ,H>rg7ᐽ6Ѧk e]ԓ{}k̸?SߙB qtG `(іRLtFH,wtWXHVmc9=2>.WR&mq>'"*tM01 1;)dEԯ2f1:acݎlz'uJpTRX `'sMJCM}+sHZQ=l0u{VG# n4/v$ρ tIԋ^2E#-.k8=j?u* "BX \(E:yYcENvLNE#]?f[hZk' |ۦyF X=#_څ[04O:.{!}mbk+eAYN$nij3tFyNzoOڏɏ82(\J@#XO Hjt;0_Pjo'}`smmz0v4|GY\In 0W.C}gɏGa IDNtAµAOY3񶾌2CHk2B.ukYGu mvf,#JXNQ_5o  E#zJLIpy.`]y)PrMCx 9,*ݘ]}@W <_ ~ m?y [w h[워-icXxƔմFd&:4M^q**Xjl"Mv|:w,â# |V0Eʠi3 P~L:U;,ft޾YW_b~yRB*ED/}W~13T3 {3b\\]ﴬnlze}lV^`T`x6Ǯ,=MPX(@Ҙ,ÈT:sFM>V~ /:(Lٌ5F=/Z';At'gDw.{Z+)J)<=m jH_ aΤ48K NYtX TfhʊŨof4iLax sY-`e_Hg{bYלt1g`m/p`٩'?7>9`%zh>)$isʼ K; :һu =EڈG:pz*dD(o{#_`&V@gx6 z'$EUĈvfт s B7ɷvHȚZ1ad4M+zWE`3آ\6uӁTb_Oċ[c+CP&@J}yȱQ!cPm&kWndѨz(rn×bl(^fdI+evƧp`P&v$Zu`t2kE`/,^|Y1L.Z$W6X}8NU_v,aF%pUuKgPVkiJ6!u*]D@:71cc^7";1j2M7cE- _o 7<#un5w5l-u8EIyK^MMUY}lF9&ձ;-ǥi&85n/bbY!ygn2U1ʹwg]Mh;mռf@7P_ӁR=/~s&\n@ ׎%$/lBK,~?űfj~=%eJ:?A[P:ĵ&吥Sb~}Y I}1os޼:K ~phHWC/}s\;y usºXRfB֓803Z`BiB^}"p"ax%K dPyz& R! CnHNr̿ 8Zoΐg ]3:mYe=bF3]P? 3ݣ k"pW8+!\.M/eb||zSۧ^|3=$<Uγ։(>[ rDZGgJ[RSEfu{[qĘl:)eÍvͷ%RzmQ\(tq6mjGWy_d`t 3ͯsc9]?yE_jh:J5 M 5QzNSkky$ʓe*l+}̧ﶜ \T;f1m`q' ,3gk1M[k4G.^Xvn00 *H  0d *H  0W@&UKX7 Pb}NaՅ*E%1ayaVO1%@@0 *H  @el"_V)gx@4k",1dTi>g LOxй*Gtrapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/keystore.jks000066400000000000000000000212341366056265300302040ustar00rootroot000000000000001i% 0 0 +* n:n<$k12a/tײ j5k`a/ieɯQ[ϤM}Kd ;6HqA䇡%[si | Z(?͵RWHVPjJG~"]qCqu3=󌔴Xix堍.K4]8`%ԖTKmbt(첉N*r/I\3/A[1)"in 2QD3?nux-F<`ƯW'ڋh{-KNfTֱ_ #ad4 G[m Gɪ].d絈6fo lD%i< yRs|ЄZ2͝a$!I<  I-ᐂoid'7 >QDiCmI\Q)i5:JUn0&PH;&9 3Ǿ  Pl7]=D/8SZooq$UnŸԈ^j˘/kY< eia9+Y:.%acCɇOHBB,eV/'RN*)z[۬!}2JFl\=>Xhhڅp} hoFj ìi>k<3Xs)N9-iJ4գY,cɡ!UtSR>znZ,=Z@<;|&~c#K|~oecb*d}gQH=l`^pfG,?0q/K n6-Q1ktfQ j0kR`MQŌm1U3)֛Y*˃@(`Bd:$oғ]&Dwf&&+sOc WDCWWuV :?hķSA3_Bfv:Fmd ={9IȥWo1ɤ]5Es}]:J. ĖA HXR39 B/cPXˁ,J H?`+>&8:H$IMAf; ǖ3SHS?ˢ7#!_:TN\&הּ`zQ 4Y ڷ3~T#Ր:<3˗F5DQ\uLwN])H`cNAdƎ) bK "Ihe\ZO͡2ZyODAi%.0P?0_o@2C`SSA w ";ǜ=K~]],<(D+7paW|Im|E#AoAUXڈ,YiKYyYU8,Xf79 ~` "n4f0I#smljJنft Xį1Fz97EOw ADel䙯Ty~6WP 2s{llWY}#BkU]SKkvTm(5N<ߧBhX>[{aHy,aVeXTL"q+R &>Mۙ*(#!lfc3$à,5~Zڰo<\MR!9_m5ݬZ]V4V!":4Ns&/PQLN`v>:ЌY-)>M"3q.[:mjC?|%U‡COp; ڰ 5Vr ʺt f'ԗR{yDK Z<6鿱L"%& $]OS#|pI@}c$nLc#2uQPأ-Ɲ?Z2֞f׌W;5"vh}(Aq(5W 2W4Ŷ͠GA<ŜQkd<uְ،Tn˨ԹΟ2r`C/B0V]OW+ct5A+)(&*=R D&;"9zY >XM&@CKɊOmmiu=.٣+C4͞j\c QJl.zUۈ윯R]n.՟i'#Bn^YRCɢ9K0scqVR<5vULPsyX.509000  *H  010U Puppet CA: localhost0 190225151740Z 290222151740Z010U localhost0"0  *H 0 H>49̜[В1|TJξl7/2{I D`UAƉF_D`,-$; Tjq Pا 虑oC)NkOͺK(D*l,y!}hn.b$zȎңQ=,pMu[F۶m83c;V[9me1¬+.mP ~Fi}޾R]o)tBg .n%5CD6<ѱ|5AkvPO+V4ִ ec\5.%q}?6wF!|L
gۋYFhU7D{$>zH>SM 9;z؉p" 8_y+؀|xêVyp])`MaN&}W}nL=|xSMM+S2 zi܏@yV>42]#sۯ|?0  *H  %w>4`)ʈJkg`~ʽqRqZJ{,Ɗ[|"lmfkBw},;T(gtD[!~׭]=@9Cz#Ce“RlTjLX;`"@ˎ76bԏűhKÉOejfp͙k/̥\)NPF}@'6ɂ,Po-[8z .7,MmUkӀuQLL^^UO\V'v-H2"=͋ &QK'kVgG=k;8yh3q|R9M5Zyc8_ {ElC1F\Mߚ:Spl/yqP WPU -[q,OgP夆tISLL(QVE 1NʘX.509 0 00  *H  010U Puppet CA: localhost0 190225143534Z 290222143534Z010U Puppet CA: localhost0"0  *H 0 '9P\0ݙXY`_ =skjrm񡋝dSݡٹj ba80gu~/ԵJ| *f9@ ( 0à `W}G=Vm7C%[*Pu'@뼖}o @G׸֬#2d%yͤsjFJdCMöJ\JmCHt(4^U`K, 2k/n^iBOm|Gy.Q9"WgS;wlIde{|P•%*nqx7S]:ihtJ:7_J ܦ0~a=cWS{r~pim3mKj "3q푷n(BK4bvkIJ3(̸ZvBH|Ky / I nH P0N0UYp*8dDh_0U#0Yp*8dDh_0 U00  *H  1y3b&(:tQExF4(I5֬2آp?'eZf]HJF vz}T޿A@;L2eú@iʫN,˘P5 t{zB,H$.ǻ9Uخhn kSTR s6EFm쇨YTlEdo{VU ߀(xA Q7rӇ:JzՍvf|YBWKj'1f%!Df2Oơv`_;KclZ8هw8%$%fmnj\XvHҩ`CvėV7s-κQ{4p ~٪-BCG1=k!_@" Nz}҅lk-5\P?c2h0@KQ4u,._/#k2ւ `QKt9Ս_G}w@ ]ﻜ:Llocalhost-puppetdb?᮷ 0 0 +* o_,!ul`Lw%hmI#Pɐ 7!l/8ǔ@)vkF8 '`SxU}jpoחQ;bM5f/0?!'t&} mahML9}X4ON۪ iR̹^օH_yF;d،lk P`^~<9xxlz+q3|߰C@uOnQ$=ٚeQK3|EuژW8Z,NI+p)9ěz=폹՘i* emKoڇE-8ʢ?&c*r&9#Xd GՏ7;ϺH6Rֳ4/z䧏͛lл :f/9=cE}h' yҠ*6=m@녎3gJ/dx x/jȻp<GUc'p;;٭"4L,4N/)Ə{G7g\k2EPUoOuxEq6fHoGj?WAaU+IC ,2aR/#8;%đ"&'ΉA*$O,`'E@\ډ {!䝀`qvpLw7`:^HC@ǥ%s-%19tOe&Z#2<"p[SJửt݅[)o.vY3)e+htR 4 dApC*d4 e)-cA7)/%Cև3^a0aP\ad|Rihvu.Kjl eI \hcuMT;;08CBmD_ cܰqTčZ{*z\c)ǗFL@uXdEY.WnM8}xm&J6M+UI*Ec4, -@*΍CEjp^jgRd7oδD'r9:!H$T"M0A'Re/+oeX(0fաA=MTv+ENA?B ȍU[-gF5NViN,R \85Qgm!#aiY|x4+.\L'L]<qÎF˛:Wlpi `ǔd"|rLןb FSB5Mt4sXS+Fb 9wNԴ#sHfgh>E;A۲S࿖RXq֙D7vΕF Hr[+M}n$Qz@/}S7.AްpoR 41$+Ͳ>~C^UIzIT$X(R=q 鋻כ4V M@fz’%3,/nVD+#[Mh r[K^Ę"*ˋ'=3Q()7.ۧ].!;u*h&'uyEJ7tR뢹3,6u^!vNJ!Ҟ5?l'tmd Sk,V$ꢛKg}L'\&:9e|Xr<`XfRe'gR`)ik4u3#tD{Pf!~TTua0i ]tI{NX,F> ⶉ,؄ҪLYCDpY0ꤠ#MB :BJ! ơ~K4 fY.ע/Ru ;j#riߪ7/tPcl7 1op z.`bx+,`}cXaAbX/w]ae)Ḱ?a Yu:Z&ynahK?`_u,m|$rEJpl?5 Lw9lgMOdtP$jWP!2뛿j徃,jg)0Cjto< Pv)iQCb` v)s4֐^w ruuNEIWt=҅CtX!NM kp^u〴v+&jR^n*Ç0 FP#wL'1.Y0\]ƑעϹ쫾@#$)s"VCbC4RSi8)ꅊbϹڂx׺(Tu& :+ JX.509W0S0;0  *H  010U Puppet CA: localhost0 130715002345Z 180715002345Z010U localhost-puppetdb0"0  *H 0 I?pP# +i B?60ܒgBC!xO'F |pdhj^ΛV0aW.o\$:S{@Hqz 6oI_Vw!c pov:E3%ր-~LF +o`䫾uLN" C7$PS`݅38YiB6} j@-Acǟ%Xq;65\ye8$>>z4 ``9ǚiz ]C$Qa^|7~YR?Zi%?YDP>I*/.8S% J&[bbCδL@x0ܮG` r 01~.007 `HB *(Puppet Ruby/OpenSSL Internal Certificate0U0 U%0++0 U00U !cFRkMed$C0  *H  -l6d8pJa:lmFIuOw5<1$ƈ7 w\zQyr.dm5DtnЫN>JF$WGj7$dF.Nrm7 ̹dU тA bۢH#/ۛQvO(rWBHC섘Ů?&rUۆF 8&U5\19TJ# s;V `[o6W XZaiB=+Moݏ<>s[vM5۩ (S#13<٥XDQwEBљ&&HMМ*Isܡj$ tjI7A)bhZtʆMR9N^UD : ڐ PKRRsrN7[f$6㺝[շ( vuøk=a!{nq 1;+`Y^&6V!Zz./\Gk-qtZ>bjMyxx,VԂ:>yt|/&|tp/8ΫS)rItߐ#m^N{CPr,5T J\Wi?]̅.%VJ8m=fm BACk;7WaE>1D2mjr4HE4H0~="|[a'+i=| Zn$R.-=pNVs F00 *H  0d *H  0W@ X4O@ B/Pqȹ"sWo5\{x~tH xIwil@@0 *H  @˄qG9Ͱ1`u{r#Bն^_` <%V(X?gVotrapperkeeper-webserver-jetty9-4.1.0/dev-resources/config/jetty/ssl/truststore.jks000066400000000000000000000025721366056265300306010ustar00rootroot00000000000000 puppetdb caE X.50960200  *H  010U Puppet CA: localhost0 140214180907Z 190214180907Z010U Puppet CA: localhost0"0  *H 0 '9P\0ݙXY`_ =skjrm񡋝dSݡٹj ba80gu~/ԵJ| *f9@ ( 0à `W}G=Vm7C%[*Pu'@뼖}o @G׸֬#2d%yͤsjFJdCMöJ\JmCHt(4^U`K, 2k/n^iBOm|Gy.Q9"WgS;wlIde{|P•%*nqx7S]:ihtJ:7_J ܦ0~a=cWS{r~pim3mKj "3q푷n(BK4bvkIJ3(̸ZvBH|Ky / I nH y0w05 `HB (Puppet Ruby/OpenSSL Internal Certificate0U0U00UYp*8dDh_0  *H  dw2jx bm0Z35Yh>xmX*@ laVtȄx%׷d{;4$tXQHQ@漞1_6CS0wӨ|t8:xXAaK.(J_ (j+Op//IۤAg&Ujg߮19nF Utȿ:z$y9rmwEmiEmeȌ RFeڐ/[#+ MP/S:8$rfh< Rrj=':wB6qezB] ~h1V6Jz#*Ȭv9e Atrapperkeeper-webserver-jetty9-4.1.0/dev-resources/helloWorld.war000066400000000000000000000041701366056265300252470ustar00rootroot00000000000000PK]MD META-INF/PKPK]MDMETA-INF/MANIFEST.MFMLK-. K-*ϳR03r.JM,IMu ě*h%&*8%krrPK@CDPK j]MDWEB-INF/PKj]MDWEB-INF/web.xmlQk0+Xq*LئC$1 3&!njmO{r{-$&G&i>>"z7_1u̬d$F4K? bKJrJ I8 @6!g-۳tMTCUɢ6Z\z!֬٫P8)^9WNڪ[j)`)сI]>0!^!&6:TMAJqż^|(7(GwTlY [[k.PK<+FPK \MD WEB-INF/src/PK\MDWEB-INF/src/HelloServlet.javaN@<Ŕ5 <d&=Sv"kvw@wwآP^ٟA,9RMU2]o v[kM=ܣ1|RV ubG0M(ZgHΜ'w(~z/Go-kjW0@޸CNºq4xf=Z9 ,&1ˍw&^-oft@u{ʼn%R?xvtMŸç"TYfe=!gW";EE;ËEvYfujCPKd|PK c\MDWEB-INF/classes/PK\MD"WEB-INF/classes/HelloServlet.classRn@=4--I m]REJT$^F7؛*,^G!f!49sf쎿 >-&`<1QPmOM<ю]U0$  \ b '$c)jc?/}Rc~H7NħTh,Hj:c`fΐvAzVON¡x) ߗ{Z*r6J(0dj @F-{xnZ 9}(O7-wˋ֜tcpbՎ1S2l" =߾?%]0j$ԁ ՘|#S5dGB!CZD{i%`#J} l!["{ |3}Zf < Hm*M7 [E, 񀲥S|H3Vތm63*lQw L:C"\L%PKS8 PK]MD META-INF/PK]MD@CD=META-INF/MANIFEST.MFPK j]MDWEB-INF/PKj]MD<+FWEB-INF/web.xmlPK \MD PWEB-INF/src/PK\MDd|zWEB-INF/src/HelloServlet.javaPK c\MDWEB-INF/classes/PK\MDS8 "WEB-INF/classes/HelloServlet.classPK_trapperkeeper-webserver-jetty9-4.1.0/dev-resources/jdk11-fips-security000066400000000000000000001276261366056265300260760ustar00rootroot00000000000000# # 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:BCFIPS 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 trapperkeeper-webserver-jetty9-4.1.0/dev-resources/jdk8-fips-security000066400000000000000000001225751366056265300260220ustar00rootroot00000000000000# # 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 subclass name 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 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. # # There must be at least one provider specification in java.security. # There is a default provider that comes standard with the JDK. It # is called the "SUN" provider, and its Provider subclass # named Sun appears in the sun.security.provider package. Thus, the # "SUN" provider is registered via the following: # # security.provider.1=sun.security.provider.Sun # # (The number 1 is used for the default provider.) # # 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:BCFIPS security.provider.3=sun.security.provider.Sun security.provider.4=sun.security.rsa.SunRsaSign #security.provider.5=sun.security.ec.SunEC #security.provider.6=com.sun.net.ssl.internal.ssl.Provider #security.provider.7=com.sun.crypto.provider.SunJCE #security.provider.8=sun.security.jgss.SunProvider #security.provider.9=com.sun.security.sasl.Provider #security.provider.10=org.jcp.xml.dsig.internal.dom.XMLDSigRI #security.provider.11=sun.security.smartcardio.SunPCSC # # Sun Provider SecureRandom seed source. # # Select the primary source of seed data for the "SHA1PRNG" and # "NativePRNG" 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" and "SHA1PRNG" 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. # # 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: # # SHA1PRNG: # the traditional system/thread activity algorithm will be used. # # 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. # # 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 # 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 # # 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. # 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}/lib/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. policy.ignoreIdentityScope=false # # Default keystore type. # keystore.type=jks # # Controls compatibility mode for the JKS keystore type. # # When set to 'true', the JKS keystore type supports loading # keystore files in either JKS or PKCS12 format. When set to 'false' # it supports loading only JKS 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 checkPackageAccess unless the # corresponding RuntimePermission ("accessClassInPackage."+package) has # been granted. package.access=sun.,\ org.GNOME.Accessibility.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.media.sound.,\ com.sun.naming.internal.,\ com.sun.proxy.,\ com.sun.corba.se.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ com.sun.org.apache.xerces.internal.,\ com.sun.org.apache.xpath.internal.,\ com.sun.org.apache.xalan.internal.extensions.,\ com.sun.org.apache.xalan.internal.lib.,\ com.sun.org.apache.xalan.internal.res.,\ com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.apache.xalan.internal.xslt.,\ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ com.sun.org.apache.xalan.internal.xsltc.compiler.,\ com.sun.org.apache.xalan.internal.xsltc.trax.,\ com.sun.org.apache.xalan.internal.xsltc.util.,\ com.sun.org.apache.xml.internal.res.,\ com.sun.org.apache.xml.internal.resolver.helpers.,\ com.sun.org.apache.xml.internal.resolver.readers.,\ com.sun.org.apache.xml.internal.security.,\ com.sun.org.apache.xml.internal.serializer.utils.,\ com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ oracle.jrockit.jfr.,\ org.jcp.xml.dsig.internal.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ jdk.xml.internal.,\ com.sun.activation.registries. # # List of comma-separated packages that start with or equal this string # will cause a security exception to be thrown when # passed to checkPackageDefinition 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.,\ com.sun.xml.internal.,\ com.sun.imageio.,\ com.sun.istack.internal.,\ com.sun.jmx.,\ com.sun.media.sound.,\ com.sun.naming.internal.,\ com.sun.proxy.,\ com.sun.corba.se.,\ com.sun.org.apache.bcel.internal.,\ com.sun.org.apache.regexp.internal.,\ com.sun.org.apache.xerces.internal.,\ com.sun.org.apache.xpath.internal.,\ com.sun.org.apache.xalan.internal.extensions.,\ com.sun.org.apache.xalan.internal.lib.,\ com.sun.org.apache.xalan.internal.res.,\ com.sun.org.apache.xalan.internal.templates.,\ com.sun.org.apache.xalan.internal.utils.,\ com.sun.org.apache.xalan.internal.xslt.,\ com.sun.org.apache.xalan.internal.xsltc.cmdline.,\ com.sun.org.apache.xalan.internal.xsltc.compiler.,\ com.sun.org.apache.xalan.internal.xsltc.trax.,\ com.sun.org.apache.xalan.internal.xsltc.util.,\ com.sun.org.apache.xml.internal.res.,\ com.sun.org.apache.xml.internal.resolver.helpers.,\ com.sun.org.apache.xml.internal.resolver.readers.,\ com.sun.org.apache.xml.internal.security.,\ com.sun.org.apache.xml.internal.serializer.utils.,\ com.sun.org.apache.xml.internal.utils.,\ com.sun.org.glassfish.,\ com.oracle.xmlns.internal.,\ com.oracle.webservices.internal.,\ oracle.jrockit.jfr.,\ org.jcp.xml.dsig.internal.,\ jdk.internal.,\ jdk.nashorn.internal.,\ jdk.nashorn.tools.,\ jdk.xml.internal.,\ com.sun.activation.registries. # # 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 3280) 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) processing # # In some environments, certain algorithms or key lengths may be undesirable # when using SSL/TLS. This section describes the mechanism for disabling # algorithms during SSL/TLS 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: 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} # Cryptographic Jurisdiction Policy defaults # # Import and export control rules on cryptographic software vary from # country to country. By default, the JDK provides two different sets of # cryptographic policy files: # # unlimited: These policy files contain no restrictions on cryptographic # strengths or algorithms. # # limited: These policy files contain more restricted cryptographic # strengths, and are still available if your country or # usage requires the traditional restrictive policy. # # The JDK JCE framework uses the unlimited policy files by default. # However the user may explicitly choose a set either by defining the # "crypto.policy" Security property or by installing valid JCE policy # jar files into the traditional JDK installation location. To better # support older JDK Update releases, the "crypto.policy" property is not # defined by default. See below for more information. # # The following logic determines which policy files are used: # # refers to the directory where the JRE was # installed and may be determined using the "java.home" # System property. # # 1. If the Security property "crypto.policy" has been defined, # then the following mechanism is used: # # The policy files are stored as jar files in subdirectories of # /lib/security/policy. Each directory contains a complete # set of policy files. # # The "crypto.policy" Security property controls the directory # selection, and thus the effective cryptographic policy. # # The default set of directories is: # # limited | unlimited # # 2. If the "crypto.policy" property is not set and the traditional # US_export_policy.jar and local_policy.jar files # (e.g. limited/unlimited) are found in the legacy # /lib/security directory, then the rules embedded within # those jar files will be used. This helps preserve compatibility # for users upgrading from an older installation. # # 3. If the jar files are not present in the legacy location # and the "crypto.policy" Security property is not defined, # then the JDK will use the unlimited settings (equivalent to # crypto.policy=unlimited) # # Please see the JCA documentation for additional information on these # files and formats. # # YOU ARE ADVISED TO CONSULT YOUR EXPORT/IMPORT CONTROL COUNSEL OR ATTORNEY # TO DETERMINE THE EXACT REQUIREMENTS. # # 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 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. # # Primitive types are not configurable with this filter. # #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. # # The maxdepth of any array passed to the RMI Registry is set to # 10000. The maximum depth of the graph is set to 20. # These limits can be reduced via the maxarray, maxdepth limits. # #sun.rmi.registry.registryFilter=pattern;pattern # # 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. # # 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. # # 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.lang.Enum;java.security.KeyRep;\ java.security.KeyRep$Type;javax.crypto.spec.SecretKeySpec;!* # # 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 trapperkeeper-webserver-jetty9-4.1.0/dev-resources/logback.xml000066400000000000000000000006211366056265300245420ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n trapperkeeper-webserver-jetty9-4.1.0/dev-resources/logging.properties000066400000000000000000000001621366056265300261620ustar00rootroot00000000000000# register SLF4JBridgeHandler as handler for the j.u.l. root logger handlers = org.slf4j.bridge.SLF4JBridgeHandlertrapperkeeper-webserver-jetty9-4.1.0/dev-resources/puppetlabs/000077500000000000000000000000001366056265300245765ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/puppetlabs/trapperkeeper/000077500000000000000000000000001366056265300274475ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/puppetlabs/trapperkeeper/services/000077500000000000000000000000001366056265300312725ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/puppetlabs/trapperkeeper/services/webserver/000077500000000000000000000000001366056265300332765ustar00rootroot00000000000000request-logging.xml000066400000000000000000000004441366056265300370570ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/dev-resources/puppetlabs/trapperkeeper/services/webserver %h %l %u %user %date "%r" %s %b %mdc{mdc-test:-default-mdc-value} trapperkeeper-webserver-jetty9-4.1.0/doc/000077500000000000000000000000001366056265300203765ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/doc/jetty-config.md000066400000000000000000000520161366056265300233260ustar00rootroot00000000000000## 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_DHE_RSA_WITH_AES_128_GCM_SHA256` - `TLS_DHE_RSA_WITH_AES_256_GCM_SHA384` - `TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384` - `TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256` - `TLS_ECDHE_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.2` When running on Java 11 users are encouraged to add `TLSv1.3` to the list of supported protocols. ### `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 Jetty9 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. ### `post-config-script` Optional. This setting is for advanced use cases only, and is intended for debugging purposes. You can use it to modify low-level Jetty settings that are not directly exposed in our normal configuration options. In most cases, if you find yourself using this, it is an indicator that we need to expose additional settings directly in our main configuration (so please let us know!). Also, the implementation details of this setting may change between releases. If you do need to use this, you can set the value to a String containing some Java code that should be executed against the Jetty `Server` object. This object will be injected into the scope of your code in a variable named `server`. Here is a pathological example that shows how you could change the port that your server listens on (which you could achieve in a much simpler fashion by using the existing `port` setting; this example is only for the purposes of illustration): post-config-script: "import org.eclipse.jetty.server.ServerConnector; ServerConnector c = (ServerConnector)(server.getConnectors()[0]); c.setPort(10000);" For more info on the Jetty `Server` object model, see the [Jetty Javadocs](http://download.eclipse.org/jetty/stable-9/apidocs/org/eclipse/jetty/server/Server.html). ## Configuring multiple webservers on isolated ports It is possible to configure multiple webservers on isolated ports within a single Jetty9 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 Jetty9 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 Jetty9 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 Jetty9 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 9 MBeans so they are visible via JMX. Useful for monitoring the state of your Jetty 9 instance while it is running; for monitoring and debugging purposes. Defaults to `true`. trapperkeeper-webserver-jetty9-4.1.0/doc/request-logging-example-config.xml000066400000000000000000000007371366056265300271370ustar00rootroot00000000000000 ./dev-resources/access.log %h %l %u [%t] "%r" %s %b "%i{Referer}" "%i{User-Agent}" trapperkeeper-webserver-jetty9-4.1.0/doc/test-utils.md000066400000000000000000000035101366056265300230340ustar00rootroot00000000000000# 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 [[puppetlabs/trapperkeeper-webserver-jetty9 "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)))) ``` trapperkeeper-webserver-jetty9-4.1.0/doc/webrouting-config.md000066400000000000000000000055311366056265300243540ustar00rootroot00000000000000## 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. trapperkeeper-webserver-jetty9-4.1.0/doc/webrouting-service.md000066400000000000000000000146621366056265300245540ustar00rootroot00000000000000## 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/puppetlabs/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/puppetlabs/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/puppetlabs/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). trapperkeeper-webserver-jetty9-4.1.0/examples/000077500000000000000000000000001366056265300214475ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/000077500000000000000000000000001366056265300246705ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/README.md000066400000000000000000000014771366056265300261600ustar00rootroot00000000000000Sample 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.trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/bootstrap.cfg000066400000000000000000000004101366056265300273610ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-service examples.multiserver-app.example-services/hello-web-service examples.multiserver-app.example-services/hello-proxy-service trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/logback.xml000066400000000000000000000004511366056265300270140ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/multiserver-example.conf000066400000000000000000000004611366056265300315520ustar00rootroot00000000000000global: { # 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 } trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/src/000077500000000000000000000000001366056265300254575ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/src/examples/000077500000000000000000000000001366056265300272755ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/multiserver_app/src/examples/multiserver_app/000077500000000000000000000000001366056265300325165ustar00rootroot00000000000000example_services.clj000066400000000000000000000030701366056265300364670ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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)))) trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/000077500000000000000000000000001366056265300232465ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/README.md000066400000000000000000000251051366056265300245300ustar00rootroot00000000000000# 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-jetty9_ 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.jetty9-service/jetty9-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 jetty9 `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. trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/bootstrap.cfg000066400000000000000000000005741366056265300257520ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-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 trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/logback.xml000066400000000000000000000004511366056265300253720ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/ring-example.conf000066400000000000000000000005211366056265300265030ustar00rootroot00000000000000global: { # 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 } trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/src/000077500000000000000000000000001366056265300240355ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/src/examples/000077500000000000000000000000001366056265300256535ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/src/examples/ring_app/000077500000000000000000000000001366056265300274525ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/src/examples/ring_app/example_services.clj000066400000000000000000000072631366056265300335120ustar00rootroot00000000000000(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)) trapperkeeper-webserver-jetty9-4.1.0/examples/ring_app/src/examples/ring_app/repl.clj000066400000000000000000000043331366056265300311110ustar00rootroot00000000000000(ns examples.ring-app.repl (:require [puppetlabs.trapperkeeper.services.webserver.jetty9-service :refer [jetty9-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 [jetty9-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))trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/000077500000000000000000000000001366056265300237735ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/README.md000066400000000000000000000004111366056265300252460ustar00rootroot00000000000000Sample 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 ``` trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/bootstrap.cfg000066400000000000000000000002011366056265300264620ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-service examples.servlet-app.servlet-app/hello-servlet-service trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/logback.xml000066400000000000000000000004511366056265300261170ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/servlet-example.conf000066400000000000000000000002301366056265300277520ustar00rootroot00000000000000global: { # Points to a logback config file logging-config: examples/servlet_app/logback.xml } webserver: { host: 0.0.0.0 port: 8080 } trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/000077500000000000000000000000001366056265300245625ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/clj/000077500000000000000000000000001366056265300253325ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/clj/examples/000077500000000000000000000000001366056265300271505ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/clj/examples/servlet_app/000077500000000000000000000000001366056265300314745ustar00rootroot00000000000000servlet_app.clj000066400000000000000000000011321366056265300344300ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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)) trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/java/000077500000000000000000000000001366056265300255035ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/java/examples/000077500000000000000000000000001366056265300273215ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/java/examples/servlet_app/000077500000000000000000000000001366056265300316455ustar00rootroot00000000000000MyServlet.java000066400000000000000000000012071366056265300343630ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/servlet_app/src/java/examples/servlet_apppackage examples.servlet_app; import java.io.IOException; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.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); } } trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/000077500000000000000000000000001366056265300231005ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/README.md000066400000000000000000000005411366056265300243570ustar00rootroot00000000000000Sample 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.trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/bootstrap.cfg000066400000000000000000000001641366056265300255770ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-service examples.war-app.war-app/hello-webservice trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/logback.xml000066400000000000000000000004511366056265300252240ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/src/000077500000000000000000000000001366056265300236675ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/src/examples/000077500000000000000000000000001366056265300255055ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/src/examples/war_app/000077500000000000000000000000001366056265300271365ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/src/examples/war_app/war_app.clj000066400000000000000000000007131366056265300312620ustar00rootroot00000000000000(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))trapperkeeper-webserver-jetty9-4.1.0/examples/war_app/war-example.conf000066400000000000000000000002321366056265300261660ustar00rootroot00000000000000global: { # Points to a logback configuration file logging-config: examples/war_app/logback.xml } webserver: { host: 0.0.0.0 port: 8080 }trapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/000077500000000000000000000000001366056265300244745ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/README.md000066400000000000000000000012431366056265300257530ustar00rootroot00000000000000Sample 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. trapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/bootstrap.cfg000066400000000000000000000007551366056265300272010ustar00rootroot00000000000000puppetlabs.trapperkeeper.services.nrepl.nrepl-service/nrepl-service puppetlabs.trapperkeeper.services.webserver.jetty9-service/jetty9-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-servicetrapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/logback.xml000066400000000000000000000004511366056265300266200ustar00rootroot00000000000000 %d %-5p [%c{2}] %m%n trapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/src/000077500000000000000000000000001366056265300252635ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/src/examples/000077500000000000000000000000001366056265300271015ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/src/examples/webrouting_app/000077500000000000000000000000001366056265300321265ustar00rootroot00000000000000example_services.clj000066400000000000000000000036471366056265300361110ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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))trapperkeeper-webserver-jetty9-4.1.0/examples/webrouting_app/webrouting-example.conf000066400000000000000000000014571366056265300311700ustar00rootroot00000000000000global: { # 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" } trapperkeeper-webserver-jetty9-4.1.0/java/000077500000000000000000000000001366056265300205525ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/000077500000000000000000000000001366056265300213305ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/000077500000000000000000000000001366056265300235075ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/000077500000000000000000000000001366056265300263605ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/000077500000000000000000000000001366056265300302035ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/000077500000000000000000000000001366056265300322075ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/jetty9/000077500000000000000000000000001366056265300334375ustar00rootroot00000000000000utils/000077500000000000000000000000001366056265300345205ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/jetty9HttpServletRequestWithAlternateRequestUri.java000066400000000000000000000014741366056265300457530ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/jetty9/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils; import javax.servlet.http.HttpServletRequest; import javax.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.java000066400000000000000000000056221366056265300425230ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/jetty9/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; import org.eclipse.jetty.util.security.CertificateUtils; import org.eclipse.jetty.util.ssl.SslContextFactory; 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 = Log.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); } } } } LifeCycleImplementingRequestLogImpl.java000066400000000000000000000031311366056265300444260ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/jetty9/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils; import ch.qos.logback.access.jetty.RequestLogImpl; import org.eclipse.jetty.util.component.LifeCycle; /* Sit down, it's story time. Once upon a time logback had a RequestLogImpl that you could just drop in Jetty and use without any modifications. Developers used this and it was good. Then, during Jetty 9.3 development, the RequestLog interface that RequestLogImpl implemented was "refactored"[0] to no longer extend Jetty's LifeCycle interface (this is distinct from Logback's LifeCycle interface, so try to keep up). Implementing Jetty's LifeCycle interface turns out to be important because Jetty uses it to decide whether or not to automatically start a Bean[1]. Many people were sad about this[2] and tried to make the RequestLogImpl again start automatically with Jetty[3], but their efforts have so far not been merged. In order for our RequestLogImpl to automatically start, we decide to extend the existing built-in logback implementation and have it implement Jetty's LifeCycle interface, which it already does, but doesn't declare. [0] - https://github.com/eclipse/jetty.project/commit/e3bda4ef [1] - https://github.com/eclipse/jetty.project/blob/0c8273f2ca1f9bf2064cd9c4c939d2546443f759/jetty-util/src/main/java/org/eclipse/jetty/util/component/ContainerLifeCycle.java#L98 [2] - https://jira.qos.ch/browse/LOGBACK-1052 [3] - https://github.com/qos-ch/logback/pull/269 And Jetty and Logback lived happily ever after. */ public class LifeCycleImplementingRequestLogImpl extends RequestLogImpl implements LifeCycle {} MDCAccessLogConverter.java000066400000000000000000000055351366056265300414520ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/jetty9/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils; import java.util.Map; import javax.servlet.http.HttpServletRequest; import ch.qos.logback.core.util.OptionHelper; import ch.qos.logback.access.pattern.AccessConverter; import ch.qos.logback.access.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 MDCRequestLogHandler class. @SuppressWarnings("unchecked") Map result = (Map) request.getAttribute(MDCRequestLogHandler.MDC_ATTR); return result; } } MDCRequestLogHandler.java000066400000000000000000000036061366056265300413040ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/java/com/puppetlabs/trapperkeeper/services/webserver/jetty9/utilspackage com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils; import java.io.IOException; import java.util.Map; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.server.handler.RequestLogHandler; import org.slf4j.MDC; /** * An implementation of the Jetty RequestLogHandler that imbues Request objects * with a copy of the SLF4J Mapped Diagnostic Context (MDC) and handles clearing * the MDC after each request. * * 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 MDCRequestLogHandler extends RequestLogHandler { public static final String MDC_ATTR = "com.puppetlabs.trapperkeeper.services.webserver.jetty9.MDC"; @Override public void handle(String target, Request baseRequest, HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // NOTE: Will return null if nothing has been set in the MDC of the worker // thread currently handling this request. Map savedContext = MDC.getCopyOfContextMap(); try { super.handle(target, baseRequest, request, response); // Tag request with a copy of the MDC so that values are accessible if // logging happens in a separate thread. Map mdcPropertyMap = MDC.getCopyOfContextMap(); baseRequest.setAttribute(MDC_ATTR, mdcPropertyMap); } finally { // Clears any context items created during the request so they don't // contaminate other requests when a worker thread is re-used. if (savedContext != null) { MDC.setContextMap(savedContext); } else { MDC.clear(); } } } } trapperkeeper-webserver-jetty9-4.1.0/jenkins/000077500000000000000000000000001366056265300212725ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/jenkins/deploy.sh000077500000000000000000000003501366056265300231230ustar00rootroot00000000000000#!/usr/bin/env bash set -e set -x git fetch --tags lein test echo "Tests passed!" lein release echo "Release plugin successful, pushing changes to git" git push origin --tags HEAD:$TK_JETTY9_BRANCH echo "git push successful." trapperkeeper-webserver-jetty9-4.1.0/locales/000077500000000000000000000000001366056265300212535ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/locales/eo.po000066400000000000000000000141511366056265300222200ustar00rootroot00000000000000# Esperanto translations for puppetlabs.trapperkeeper_webserver_jetty9 package. # Copyright (C) 2017 Puppet # This file is distributed under the same license as the puppetlabs.trapperkeeper_webserver_jetty9 package. # Automatically generated, 2017. # msgid "" msgstr "" "Project-Id-Version: puppetlabs.trapperkeeper_webserver_jetty9 \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/jetty9_websockets.clj msgid "No handler defined for websocket event ''{0}'' with args: ''{1}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_config.clj msgid "Unable to open ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "No certs found in ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Unable to open ''ssl-cert-chain'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_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/jetty9_config.clj msgid "" "Unexpected value found for client auth config option: {0}. Expected need, " "want, or none." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Non-readable path specified for ssl-crl-path option: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Error: More than one default server specified in configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_config.clj msgid "" "The ''post-config-script'' setting is for advanced use cases only, and may " "be subject to minor changes when the application is upgraded." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Invalid script string in webserver ''post-config-script'' configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Removing buggy security provider {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Could not remove security providers; HTTPS may not work!" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "webserver config overridden for key ''{0}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_core.clj msgid "{0} proxying failed" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "{0} could not close the connection" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Cleaning up JMX MBean container" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Shutting down web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "" "Web server failed to shut down gracefully in configured timeout period " "({0}); cancelling remaining requests." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Web server shutdown" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Starting web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Encountered error starting web server, so shutting down" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "" "overrides cannot be set because webserver has already processed the config" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_core.clj msgid "overrides cannot be set because they have already been set" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_service.clj msgid "Initializing web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_service.clj msgid "Starting web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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 "" trapperkeeper-webserver-jetty9-4.1.0/locales/trapperkeeper-webserver-jetty9.pot000066400000000000000000000150321366056265300301010ustar00rootroot00000000000000# SOME DESCRIPTIVE TITLE. # Copyright (C) YEAR Puppet # This file is distributed under the same license as the PACKAGE package. # FIRST AUTHOR , YEAR. # #, fuzzy msgid "" msgstr "" "Project-Id-Version: puppetlabs.trapperkeeper_webserver_jetty9 \n" "X-Git-Ref: febbde781f04fe3ebf782cf2ceaf32ae8da7e3f8\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/experimental/jetty9_websockets.clj msgid "No handler defined for websocket event ''{0}'' with args: ''{1}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_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/jetty9_config.clj msgid "Unable to open ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "No certs found in ''ssl-cert'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Unable to open ''ssl-cert-chain'' file: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_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/jetty9_config.clj msgid "" "Unexpected value found for client auth config option: {0}. Expected need, " "want, or none." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Non-readable path specified for ssl-crl-path option: {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Error: More than one default server specified in configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_config.clj msgid "" "The ''post-config-script'' setting is for advanced use cases only, and may " "be subject to minor changes when the application is upgraded." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_config.clj msgid "Invalid script string in webserver ''post-config-script'' configuration" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Removing buggy security provider {0}" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Could not remove security providers; HTTPS may not work!" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "logging-router.properties not found, extra logging will occur" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "webserver config overridden for key ''{0}''" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "" "`ssl-protocols` contains SSLv3, a protocol with known vulnerabilities; " "ignoring" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "When `ssl-protocols` is empty, a default of {0} is assumed" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "{0} proxying failed" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "{0} could not close the connection" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Cleaning up JMX MBean container" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Shutting down web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "" "Web server failed to shut down gracefully in configured timeout period " "({0}); cancelling remaining requests." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Web server shutdown" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Starting web server." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "Encountered error starting web server, so shutting down" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj msgid "" "overrides cannot be set because webserver has already processed the config" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_core.clj msgid "overrides cannot be set because they have already been set" msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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/jetty9_service.clj msgid "Initializing web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_service.clj msgid "Starting web server(s)." msgstr "" #: src/puppetlabs/trapperkeeper/services/webserver/jetty9_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 "" trapperkeeper-webserver-jetty9-4.1.0/project.clj000066400000000000000000000145071366056265300220000ustar00rootroot00000000000000(def jetty-version "9.4.28.v20200408") (defproject puppetlabs/trapperkeeper-webserver-jetty9 "4.1.0" :description "A jetty9-based webserver implementation for use with the puppetlabs/trapperkeeper service framework." :url "https://github.com/puppetlabs/trapperkeeper-webserver-jetty9" :license {:name "Apache License, Version 2.0" :url "http://www.apache.org/licenses/LICENSE-2.0"} :min-lein-version "2.8.1" :parent-project {:coords [puppetlabs/clj-parent "4.2.4"] :inherit [:managed-dependencies]} ;; 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 :dependencies [[org.clojure/clojure] [org.clojure/java.jmx] [org.clojure/tools.logging] [org.codehaus.janino/janino] [org.flatland/ordered "1.5.7"] [javax.servlet/javax.servlet-api "3.1.0"] ;; Jetty Webserver [org.eclipse.jetty/jetty-server ~jetty-version :exclusions [org.eclipse.jetty.orbit/javax.servlet]] [org.eclipse.jetty/jetty-servlet ~jetty-version] [org.eclipse.jetty/jetty-servlets ~jetty-version] [org.eclipse.jetty/jetty-webapp ~jetty-version] [org.eclipse.jetty/jetty-proxy ~jetty-version] [org.eclipse.jetty/jetty-jmx ~jetty-version] [org.eclipse.jetty.websocket/websocket-server ~jetty-version] [prismatic/schema] [ring/ring-servlet] [ring/ring-codec] [puppetlabs/ssl-utils] [puppetlabs/kitchensink] [puppetlabs/trapperkeeper] [puppetlabs/i18n] [puppetlabs/trapperkeeper-filesystem-watcher] [org.slf4j/jul-to-slf4j]] :source-paths ["src"] :java-source-paths ["java"] :plugins [[lein-parent "0.3.7"] [puppetlabs/i18n "0.8.0"]] :deploy-repositories [["releases" {:url "https://clojars.org/repo" :username :env/clojars_jenkins_username :password :env/clojars_jenkins_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 {:defaults {: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 [[puppetlabs/http-client] [puppetlabs/kitchensink nil :classifier "test"] [puppetlabs/trapperkeeper nil :classifier "test"] [org.clojure/tools.namespace] [compojure] [stylefruits/gniazdo "1.1.1" :exclusions [org.eclipse.jetty.websocket/websocket-api org.eclipse.jetty.websocket/websocket-client org.eclipse.jetty/jetty-util]] [ring/ring-core]] :resource-paths ["dev-resources"] :jvm-opts ["-Djava.util.logging.config.file=dev-resources/logging.properties"]} :dev [:defaults {:dependencies [[org.bouncycastle/bcpkix-jdk15on]]}] ;; per https://github.com/technomancy/leiningen/issues/1907 ;; the provided profile is necessary for lein jar / lein install :provided {:dependencies [[org.bouncycastle/bcpkix-jdk15on]] :resource-paths ["dev-resources"]} :fips [:defaults ; merge in the dev profile {:dependencies [[org.bouncycastle/bcpkix-fips] [org.bouncycastle/bc-fips] [org.bouncycastle/bctls-fips]] :exclusions [[org.bouncycastle/bcpkix-jdk15on]] ;; 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. :jvm-opts ~(let [version (System/getProperty "java.version") [major minor _] (clojure.string/split version #"\.") unsupported-ex (ex-info "Unsupported major Java version. Expects 8 or 11." {:major major :minor minor})] (condp = (java.lang.Integer/parseInt major) 1 (if (= 8 (java.lang.Integer/parseInt minor)) ["-Djava.security.properties==dev-resources/jdk8-fips-security"] (throw unsupported-ex)) 11 ["-Djava.security.properties==dev-resources/jdk11-fips-security"] (throw unsupported-ex)))}] :testutils {:source-paths ^:replace ["test/clj"] :java-source-paths ^:replace ["test/java"]}} :main puppetlabs.trapperkeeper.main :repositories [["puppet-releases" "https://artifactory.delivery.puppetlabs.net/artifactory/list/clojure-releases__local/"] ["puppet-snapshots" "https://artifactory.delivery.puppetlabs.net/artifactory/list/clojure-snapshots__local/"]] ) trapperkeeper-webserver-jetty9-4.1.0/resources/000077500000000000000000000000001366056265300216435ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/resources/logging-router.properties000066400000000000000000000003501366056265300267230ustar00rootroot00000000000000# 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 trapperkeeper-webserver-jetty9-4.1.0/src/000077500000000000000000000000001366056265300204205ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/000077500000000000000000000000001366056265300225775ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/experimental/000077500000000000000000000000001366056265300252745ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/experimental/websockets/000077500000000000000000000000001366056265300274455ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/experimental/websockets/client.clj000066400000000000000000000015701366056265300314200ustar00rootroot00000000000000(ns puppetlabs.experimental.websockets.client) (defprotocol WebSocketProtocol "Functions to manage the lifecycle of a websocket session" (idle-timeout! [this ms] "Set the idle timeout for the session, in milliseconds") (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.") (disconnect [this] "Disconnect the websocket connection") (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")) trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/000077500000000000000000000000001366056265300254505ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/000077500000000000000000000000001366056265300272735ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webrouting/000077500000000000000000000000001366056265300314605ustar00rootroot00000000000000webrouting_service.clj000066400000000000000000000144471366056265300360120ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service (:require [clojure.tools.logging :as log] [puppetlabs.trapperkeeper.services :refer [service-context]] [puppetlabs.trapperkeeper.services.webrouting.webrouting-service-core :as core] [puppetlabs.trapperkeeper.core :refer [defservice]] [schema.core :as schema])) (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-websocket-handler [this svc handlers] [this svc handlers 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 jetty9 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-websocket-handler [this svc handlers] (core/add-websocket-handler! (service-context this) WebserverService svc handlers {})) (add-websocket-handler [this svc handlers options] (core/add-websocket-handler! (service-context this) WebserverService svc handlers 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.clj000066400000000000000000000155211366056265300370140ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-core (:require [schema.core :as schema] [puppetlabs.trapperkeeper.services.webserver.jetty9-core :as jetty9-core] [puppetlabs.trapperkeeper.services :as tk-services] [puppetlabs.i18n.core :as i18n])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 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 jetty9-core/CommonOptions RouteOption) :server-id)) (def ContextHandlerOptions (dissoc (merge jetty9-core/ContextHandlerOptions RouteOption) :server-id)) (def ServletHandlerOptions (dissoc (merge jetty9-core/ServletHandlerOptions RouteOption) :server-id)) (def ProxyRouteOptions (dissoc (merge jetty9-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-websocket-handler! [context webserver-service svc :- (schema/protocol tk-services/Service) handlers options :- CommonOptions] (let [{:keys [path opts]} (compute-common-elements context svc options) add-websocket-handler (:add-websocket-handler webserver-service)] (add-websocket-handler handlers 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))) trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webserver/000077500000000000000000000000001366056265300312775ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webserver/experimental/000077500000000000000000000000001366056265300337745ustar00rootroot00000000000000jetty9_websockets.clj000066400000000000000000000113031366056265300400660ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webserver/experimental(ns puppetlabs.trapperkeeper.services.webserver.experimental.jetty9-websockets (:import (clojure.lang IFn) (org.eclipse.jetty.server Request) (org.eclipse.jetty.websocket.api WebSocketAdapter Session) (org.eclipse.jetty.websocket.server WebSocketHandler) (org.eclipse.jetty.websocket.servlet WebSocketServletFactory WebSocketCreator) (java.security.cert X509Certificate) (java.nio ByteBuffer)) (:require [clojure.tools.logging :as log] [puppetlabs.experimental.websockets.client :refer [WebSocketProtocol]] [schema.core :as schema] [puppetlabs.i18n.core :as i18n])) (def WebsocketHandlers {(schema/optional-key :on-connect) IFn (schema/optional-key :on-error) IFn (schema/optional-key :on-close) IFn (schema/optional-key :on-text) IFn (schema/optional-key :on-bytes) IFn}) (defprotocol WebSocketSend (-send! [x ws] "How to encode content sent to the WebSocket clients")) (extend-protocol WebSocketSend (Class/forName "[B") (-send! [ba ws] (-send! (ByteBuffer/wrap ba) ws)) ByteBuffer (-send! [bb ws] (-> ^WebSocketAdapter ws .getRemote (.sendBytes ^ByteBuffer bb))) String (-send! [s ws] (-> ^WebSocketAdapter ws .getRemote (.sendString ^String s)))) (extend-protocol WebSocketProtocol WebSocketAdapter (send! [this msg] (-send! msg this)) (close! ([this] (.. this (getSession) (close))) ([this code reason] (.. this (getSession) (close code reason)))) (disconnect [this] (when-let [session (.getSession this)] (.disconnect session))) (remote-addr [this] (.. this (getSession) (getRemoteAddress))) (ssl? [this] (.. this (getSession) (getUpgradeRequest) (isSecure))) (peer-certs [this] (.. this (getCerts))) (request-path [this] (.. this (getRequestPath))) (idle-timeout! [this ms] (.. this (getSession) (setIdleTimeout ^long ms))) (connected? [this] (. this (isConnected)))) (definterface CertGetter (^Object getCerts []) (^String getRequestPath [])) (defn no-handler [event & args] (log/debug (i18n/trs "No handler defined for websocket event ''{0}'' with args: ''{1}''" event args))) (schema/defn ^:always-validate proxy-ws-adapter :- WebSocketAdapter [handlers :- WebsocketHandlers x509certs :- [X509Certificate] requestPath :- String] (let [{:keys [on-connect on-error on-text on-close on-bytes] :or {on-connect (partial no-handler :on-connect) on-error (partial no-handler :on-error) on-text (partial no-handler :on-text) on-close (partial no-handler :on-close) on-bytes (partial no-handler :on-bytes)}} handlers] (proxy [WebSocketAdapter CertGetter] [] (onWebSocketConnect [^Session session] (let [^WebSocketAdapter this this] (proxy-super onWebSocketConnect session)) (on-connect this)) (onWebSocketError [^Throwable e] (let [^WebSocketAdapter this this] (proxy-super onWebSocketError e)) (on-error this e)) (onWebSocketText [^String message] (let [^WebSocketAdapter this this] (proxy-super onWebSocketText message)) (on-text this message)) (onWebSocketClose [statusCode ^String reason] (let [^WebSocketAdapter this this] (proxy-super onWebSocketClose statusCode reason)) (on-close this statusCode reason)) (onWebSocketBinary [^bytes payload offset len] (let [^WebSocketAdapter this this] (proxy-super onWebSocketBinary payload offset len)) (on-bytes this payload offset len)) (getCerts [] x509certs) (getRequestPath [] requestPath)))) (schema/defn ^:always-validate proxy-ws-creator :- WebSocketCreator [handlers :- WebsocketHandlers] (reify WebSocketCreator (createWebSocket [this req _] (let [x509certs (vec (.. req (getCertificates))) requestPath (.. req (getRequestPath))] (proxy-ws-adapter handlers x509certs requestPath))))) (schema/defn ^:always-validate websocket-handler :- WebSocketHandler "Returns a Jetty WebSocketHandler implementation for the given set of Websocket handlers" [handlers :- WebsocketHandlers] (proxy [WebSocketHandler] [] (configure [^WebSocketServletFactory factory] (.setCreator factory (proxy-ws-creator handlers))) (handle [^String target, ^Request request req res] (let [wsf (proxy-super getWebSocketFactory)] (if (.isUpgradeRequest wsf req res) (if (.acceptWebSocket wsf req res) (.setHandled request true) (when (.isCommitted res) (.setHandled request true))) (proxy-super handle target request req res)))))) jetty9_config.clj000066400000000000000000000502761366056265300345010ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-config (:import (java.security KeyStore) (java.io FileInputStream) (java.util HashMap) (ch.qos.logback.access PatternLayout) (ch.qos.logback.core CoreConstants) (org.eclipse.jetty.server.handler RequestLogHandler) (org.eclipse.jetty.server Server) (org.codehaus.janino ScriptEvaluator) (org.codehaus.commons.compiler CompileException) (java.lang.reflect InvocationTargetException) (com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils LifeCycleImplementingRequestLogImpl MDCAccessLogConverter MDCRequestLogHandler) (com.puppetlabs.ssl_utils SSLUtils)) (:require [clojure.tools.logging :as log] [clojure.string :as str] [me.raynes.fs :as fs] [schema.core :as schema] [puppetlabs.ssl-utils.core :as ssl] [puppetlabs.kitchensink.core :refer [missing? num-cpus uuid parse-bool]] [puppetlabs.i18n.core :as i18n])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 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 ;;; `jetty9_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-j9 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 acceptable-ciphers ["TLS_DHE_RSA_WITH_AES_128_GCM_SHA256" "TLS_DHE_RSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256" "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"]) (def acceptable-ciphers-fips ["TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256" "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384" "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"]) (def default-protocols ["TLSv1.2"]) (def default-client-auth :need) (def default-allow-renegotiation false) ;;; ;;; JMX ;;; ;;; The JMX metrics seem valuable enough, and inexpensive enough, to warrant ;;; leaving them on by default. (def default-jmx-enable "true") ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 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 :post-config-script) schema/Str (schema/optional-key :allow-renegotiation) 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)}) (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 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. (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. keystore) (.toCharArray key-password))) :truststore (doto (ssl/keystore) (.load (FileInputStream. 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)}))) (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] (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. (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 :- RequestLogHandler [config :- WebserverRawConfig] (let [handler (MDCRequestLogHandler.) pattern-rules (HashMap.) logger (LifeCycleImplementingRequestLogImpl.)] (doseq [pattern ["X" "mdc"]] (.put pattern-rules pattern (.getName MDCAccessLogConverter))) (.putObject logger CoreConstants/PATTERN_RULE_REGISTRY pattern-rules) (.setFileName logger (:access-log-config config)) (.setQuiet logger true) (.setRequestLog handler logger) handler)) (defn maybe-init-log-handler [config] (if (:access-log-config config) (init-log-handler config))) (schema/defn ^:always-validate execute-post-config-script! [s :- Server script :- schema/Str] (log/warn (i18n/trs "The ''post-config-script'' setting is for advanced use cases only, and may be subject to minor changes when the application is upgraded.")) (let [script-err-msg (i18n/trs "Invalid script string in webserver ''post-config-script'' configuration")] (try (let [evaluator (doto (ScriptEvaluator.) (.setParameters (into-array String ["server"]) (into-array Class [Server])) (.cook script))] (.evaluate evaluator (into-array Object [s]))) (catch CompileException ex (throw (IllegalArgumentException. script-err-msg ex))) (catch InvocationTargetException ex (throw (IllegalArgumentException. script-err-msg ex)))))) trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webserver/jetty9_core.clj000066400000000000000000001462471366056265300342470ustar00rootroot00000000000000(ns puppetlabs.trapperkeeper.services.webserver.jetty9-core (:import (org.eclipse.jetty.server Handler Server Request ServerConnector HttpConfiguration HttpConnectionFactory ConnectionFactory AbstractConnectionFactory) (org.eclipse.jetty.server.handler AbstractHandler ContextHandler HandlerCollection ContextHandlerCollection AllowSymLinkAliasChecker StatisticsHandler HandlerWrapper) (org.eclipse.jetty.server.handler.gzip GzipHandler) (org.eclipse.jetty.util.resource Resource) (org.eclipse.jetty.util.thread QueuedThreadPool) (org.eclipse.jetty.util.ssl SslContextFactory) (javax.servlet.http HttpServletResponse) (java.util.concurrent TimeoutException) (org.eclipse.jetty.servlet ServletContextHandler ServletHolder DefaultServlet) (org.eclipse.jetty.webapp WebAppContext) (org.eclipse.jetty.http MimeTypes HttpHeader HttpHeaderValue HttpMethod) (javax.servlet Servlet ServletContextListener) (org.eclipse.jetty.proxy ProxyServlet) (java.net URI) (java.security Security) (org.eclipse.jetty.client HttpClient RedirectProtocolHandler) (clojure.lang Atom) (java.lang.management ManagementFactory) (org.eclipse.jetty.jmx MBeanContainer) (org.eclipse.jetty.util URIUtil BlockingArrayQueue) (java.io IOException) (com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils InternalSslContextFactory) (com.puppetlabs.ssl_utils SSLUtils)) (:require [ring.util.servlet :as servlet] [ring.util.codec :as codec] [clojure.string :as str] [clojure.tools.logging :as log] [puppetlabs.trapperkeeper.services.webserver.jetty9-config :as config] [puppetlabs.trapperkeeper.services.webserver.experimental.jetty9-websockets :as websockets] [puppetlabs.trapperkeeper.services.webserver.normalized-uri-helpers :as normalized-uri-helpers] [puppetlabs.trapperkeeper.services.protocols.filesystem-watch-service :as watch-protocol] [schema.core :as schema] [puppetlabs.i18n.core :as i18n] [me.raynes.fs :as fs])) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; 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-renegotiations) (schema/maybe [schema/Bool])})) (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 :failure-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) (schema/both schema/Int (schema/pred pos?)))) (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 WebsocketEndpoint {:type (schema/eq :websocket)}) (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 (= :websocket)) WebsocketEndpoint #(-> % :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-factory (schema/maybe InternalSslContextFactory)}) (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))) (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] (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))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;; SSL Context Functions (schema/defn ^:always-validate ssl-context-factory :- SslContextFactory "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]} :- config/WebserverSslContextFactory] (if (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)) (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 [ssl-config :- ProxySslConfig] (ssl-context-factory {:keystore-config (config/pem-ssl-config->keystore-ssl-config ssl-config) :client-auth :none :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 [http-config (doto (HttpConfiguration.) (.setSendDateHeader true) (.setSendServerVersion false))] (if request-header-size (.setRequestHeaderSize http-config request-header-size)) http-config)) (defn- connection-factories [request-header-size 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)] (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 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 [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-factory (ssl-context-factory (select-keys https [:keystore-config :client-auth :ssl-crl-path :cipher-suites :allow-renegotiation :protocols])) connector (ssl-connector server ssl-ctxt-factory https)] (.addConnector server connector) (swap! (:state webserver-context) assoc :ssl-context-factory ssl-ctxt-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." [] (-> ;; This code is ported from Jetty 9.0.5's GzipFilter class. In ;; Jetty 7, this behavior was the default for GzipHandler as well ;; as GzipFilter, but in Jetty 9.0.5 the GzipHandler no longer ;; includes this, so we need to do it by hand. (filter #(or (.startsWith % "image/") (.startsWith % "audio/") (.startsWith % "video/")) (MimeTypes/getKnownMimeTypes)) (conj "application/compress" "application/zip" "application/gzip" "text/event-stream") (into-array))) (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 handler :- ContextHandler enable-trailing-slash-redirect? :- schema/Bool] (.setAllowNullPathInfo 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) (defn- ring-handler "Returns an Jetty Handler implementation for the given Ring handler." [handler] (proxy [AbstractHandler] [] (handle [_ ^Request base-request request response] (let [request-map (servlet/build-request-map request) response-map (handler request-map)] (when response-map (servlet/update-servlet-response response response-map) (.setHandled base-request true)))))) (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 (when (map? (:ssl-config options)) (get-proxy-client-context-factory (:ssl-config options))) {: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 (HttpClient. custom-ssl-ctxt-factory) (if-let [ssl-ctxt-factory (:ssl-context-factory @(:state webserver-context))] (HttpClient. ssl-ctxt-factory) (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 resp proxy-req] (if-let [callback-fn (:callback-fn options)] (callback-fn proxy-req req)) (proxy-super sendProxyRequest req resp proxy-req)) ;; The implementation of onResponseFailure is duplicated heavily from: ;; https://github.com/eclipse/jetty.project/blob/jetty-9.4.1.v20170120/jetty-proxy/src/main/java/org/eclipse/jetty/proxy/AbstractProxyServlet.java#L624-L658 ;; The only significant difference is that a 'failure-callback-fn', if ;; defined in options, is invoked just prior to completing the async ;; context for cases that the response was not already committed upstream. (onProxyResponseFailure [req resp proxy-resp failure] (do (let [request-id (.getRequestId this req) async-context (.getAsyncContext req)] (log/debug failure (i18n/trs "{0} proxying failed" request-id)) (if (.isCommitted resp) (try (.sendError resp -1) (.complete async-context) (catch IOException _ (log/debug failure (i18n/trs "{0} could not close the connection" request-id)))) (do (.resetBuffer resp) (if (instance? TimeoutException failure) (.setStatus resp HttpServletResponse/SC_GATEWAY_TIMEOUT) (.setStatus resp HttpServletResponse/SC_BAD_GATEWAY)) (.setHeader resp (.asString HttpHeader/CONNECTION) (.asString HttpHeaderValue/CLOSE)) (when-let [failure-callback-fn (:failure-callback-fn options)] (failure-callback-fn req resp proxy-resp failure)) (.complete async-context))))))))) (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 [HandlerWrapper] [] (handle [target ^Request base-request request response] (let [request-size (.getContentLength base-request)] (if (> request-size max-size) (do (.setStatus response HttpServletResponse/SC_REQUEST_ENTITY_TOO_LARGE) (.setHandled base-request true)) (.handle handler target base-request request response)))))) (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 HandlerCollection and a ContextHandlerCollection which can accept the addition of new handlers before the webserver is started." [] (let [^ContextHandlerCollection chc (ContextHandlerCollection.)] {:handlers chc :state (atom {:endpoints {} :mbean-container nil :overrides-read-by-webserver false :overrides nil :ssl-context-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] :as webserver-context} :- ServerContext] (when-let [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))))) (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) ^HandlerCollection hc (HandlerCollection.) log-handler (config/maybe-init-log-handler options)] (.setHandlers hc (into-array Handler [(:handlers webserver-context)])) (let [shutdown-timeout (when (not (nil? (:shutdown-timeout-seconds options))) (* 1000 (:shutdown-timeout-seconds options))) 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 log-handler (doto log-handler (.setHandler maybe-size-restricted)) maybe-size-restricted) statistics-handler (if (or (nil? shutdown-timeout) (pos? shutdown-timeout)) (doto (StatisticsHandler.) (.setHandler maybe-logged)) maybe-logged)] (.setHandler s statistics-handler) (when shutdown-timeout (.setStopTimeout s shutdown-timeout)) (when-let [script (:post-config-script options)] (config/execute-post-config-script! s script)) (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 ^:always-validate add-context-handler :- ContextHandler "Add a static content context handler (allow for customization of the context handler through javax.servlet.ServletContextListener implementations)" ([webserver-context base-path context-path] (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] (let [handler (ServletContextHandler. nil context-path ServletContextHandler/NO_SESSIONS) follow-links? (:follow-links? options) enable-trailing-slash-redirect? (:enable-trailing-slash-redirect? options) normalize-request-uri? (:normalize-request-uri? options)] (.setBaseResource handler (Resource/newResource ^String base-path)) (if follow-links? (.setAliasChecks handler [(AllowSymLinkAliasChecker.)]) (.clearAliasChecks handler)) ;; register servlet context listeners (if any) (when-not (nil? context-listeners) (dorun (map #(.addEventListener handler %) context-listeners))) (.addServlet handler (ServletHolder. (DefaultServlet.)) "/") (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-ring-handler :- ContextHandler [webserver-context :- ServerContext handler :- (schema/pred ifn? 'ifn?) path :- schema/Str enable-trailing-slash-redirect? :- schema/Bool normalize-request-uri? :- schema/Bool] (let [handler (normalized-uri-helpers/handler-maybe-wrapped-with-normalized-uri (ring-handler handler) normalize-request-uri?) path (if (= "" path) "/" path) ctxt-handler (doto (ContextHandler. path) (.setHandler handler))] (add-handler webserver-context ctxt-handler enable-trailing-slash-redirect?))) (schema/defn ^:always-validate add-websocket-handler :- ContextHandler [webserver-context :- ServerContext handlers :- websockets/WebsocketHandlers path :- schema/Str enable-trailing-slash-redirect? :- schema/Bool normalize-request-uri? :- schema/Bool] (let [handler (normalized-uri-helpers/handler-maybe-wrapped-with-normalized-uri (websockets/websocket-handler handlers) normalize-request-uri?) ctxt-handler (doto (ContextHandler. path) (.setHandler 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) and :failure-callback-fn (a function taking four arguments, `[req resp proxy-resp failure]`, see README.md/#failure-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. (i18n/trs "overrides cannot be set because webserver has already processed the config"))) (throw (IllegalStateException. (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. (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 (:jetty9-servers context)) webserver (start-webserver! default-context config) server-context-list (assoc (:jetty9-servers context) :default webserver)] (assoc context :jetty9-servers server-context-list))) (defn start-server-multiple [context config] (let [context-seq (for [[server-id server-context] (:jetty9-servers context)] [server-id (start-webserver! server-context (server-id config))])] (assoc context :jetty9-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. (i18n/trs "no server-id was specified for this operation and no default server was specified in the configuration")))) (server-id (:jetty9-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 :jetty9-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))] (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) (.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 :jetty9-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-websocket-handler! [context handlers :- websockets/WebsocketHandlers path :- schema/Str options :- CommonOptions] (let [server-id (:server-id options) s (get-server-context context server-id) state (:state s) endpoint-map {:type :websocket} 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-websocket-handler s handlers 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))) jetty9_service.clj000066400000000000000000000150171366056265300346660ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-service (:require [clojure.tools.logging :as log] [puppetlabs.trapperkeeper.services.webserver.jetty9-config :as config] [puppetlabs.trapperkeeper.services.webserver.jetty9-core :as core] [puppetlabs.trapperkeeper.services.protocols.filesystem-watch-service :as watch-protocol] [puppetlabs.trapperkeeper.services :refer [get-service maybe-get-service service-context]] [puppetlabs.trapperkeeper.config :as tk-config] [puppetlabs.trapperkeeper.core :refer [defservice]] [puppetlabs.i18n.core :as i18n] [me.raynes.fs :as fs])) ;; 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-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])) (defservice jetty9-service "Provides a Jetty 9 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]) {}) started-context (core/start! context config)] (if-let [filesystem-watcher-service (maybe-get-service this :FilesystemWatchService)] (let [watcher (watch-protocol/create-watcher filesystem-watcher-service {:recursive false})] (doseq [server (:jetty9-servers started-context)] (when-let [ssl-context-factory (-> server second :state deref :ssl-context-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 (:jetty9-servers context))] (if-let [server (key (:jetty9-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-websocket-handler [this handlers path] (core/add-websocket-handler! (service-context this) handlers path {})) (add-websocket-handler [this handlers path options] (core/add-websocket-handler! (service-context this) handlers 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.clj000066400000000000000000000145061366056265300364650ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/src/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.normalized-uri-helpers (:import (javax.servlet.http HttpServletRequest HttpServletResponse) (org.eclipse.jetty.util URIUtil) (org.eclipse.jetty.server Request) (org.eclipse.jetty.server.handler HandlerWrapper AbstractHandler) (com.puppetlabs.trapperkeeper.services.webserver.jetty9.utils HttpServletRequestWithAlternateRequestUri) (javax.servlet Filter DispatcherType) (java.util EnumSet) (org.eclipse.jetty.servlet FilterHolder ServletContextHandler)) (:require [schema.core :as schema] [ring.util.servlet :as servlet] [clojure.string :as str] [puppetlabs.i18n.core :as i18n])) (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] (let [percent-decoded-uri-path (-> request (.getRequestURI) (URIUtil/decodePath)) canonicalized-uri-path (URIUtil/canonicalPath percent-decoded-uri-path)] (if (or (nil? canonicalized-uri-path) (not= (.length percent-decoded-uri-path) (.length canonicalized-uri-path))) (throw (IllegalArgumentException. (i18n/trs "Invalid relative path (.. or .) in: {0}" percent-decoded-uri-path))) (URIUtil/compactPath canonicalized-uri-path)))) (schema/defn ^:always-validate normalize-uri-handler :- HandlerWrapper "Create a `HandlerWrapper` which provides a normalized request URI on to its downstream handler for an incoming request. The normalized URI would be returned for a 'getRequestURI' call made by the downstream handler on its incoming HttpServletRequest request 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 handler." [] (proxy [HandlerWrapper] [] (handle [^String target ^Request base-request ^HttpServletRequest request ^HttpServletResponse response] (when-let [handler (proxy-super getHandler)] (if-let [normalized-uri (try (normalize-uri-path request) (catch IllegalArgumentException ex (do (servlet/update-servlet-response response {:status 400 :body (.getMessage ex)}) (.setHandled base-request true)) nil))] (.handle handler target base-request (HttpServletRequestWithAlternateRequestUri. request normalized-uri) response)))))) (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 :- AbstractHandler "If the supplied `normalize-request-uri?` parameter is 'true', return a handler that normalizes a request uri before passing it on downstream to the supplied handler for an incoming request. If the supplied `normalize-request-uri?` is 'false', return the supplied handler." [handler :- AbstractHandler normalize-request-uri? :- schema/Bool] (if normalize-request-uri? (doto (normalize-uri-handler) (.setHandler handler)) handler)) trapperkeeper-webserver-jetty9-4.1.0/test/000077500000000000000000000000001366056265300206105ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/000077500000000000000000000000001366056265300213605ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/000077500000000000000000000000001366056265300235375ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/000077500000000000000000000000001366056265300264105ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/000077500000000000000000000000001366056265300302335ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webrouting/000077500000000000000000000000001366056265300324205ustar00rootroot00000000000000webrouting_service_handlers_test.clj000066400000000000000000000227111366056265300416620ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-handlers-test (:import (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.jetty9-service :refer [jetty9-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 (testing "static content context with web routing" (with-app-with-config app [jetty9-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 [jetty9-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 (testing "ring request over http succeeds with web-routing" (with-app-with-config app [jetty9-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 [jetty9-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 (testing "request to servlet over http succeeds with web routing" (with-app-with-config app [jetty9-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) svc (get-service app :TestDummy)] (add-servlet-handler svc servlet) (let [response (http-get "http://localhost:8080/foo")] (is (= (:status response) 200)) (is (= (:body response) body)))))) (testing "request to servlet over http succeeds with multiple web routes" (with-app-with-config app [jetty9-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) 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 (= (:body response) body))) (let [response (http-get "http://localhost:8080/bar")] (is (= (:status response) 200)) (is (= (:body response) body))))))) (deftest war-test-web-routing (testing "WAR support with web routing" (with-app-with-config app [jetty9-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 [jetty9-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 [jetty9-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))))))) webrouting_service_override_settings_test.clj000066400000000000000000000112311366056265300436140ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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.jetty9-service :refer [jetty9-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 [jetty9-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.clj000066400000000000000000000100551366056265300412410ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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.jetty9-service :refer [jetty9-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.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-app-with-config proxy-target-app# [jetty9-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# [jetty9-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.clj000066400000000000000000000177101366056265300400050ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webrouting(ns puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test (:require [clojure.test :refer :all] [clojure.tools.logging :as log] [gniazdo.core :as ws-client] [puppetlabs.experimental.websockets.client :as ws-session] [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.webrouting.webrouting-service :refer :all] [puppetlabs.trapperkeeper.services.webserver.jetty9-service :refer [jetty9-service]] [puppetlabs.trapperkeeper.testutils.webrouting.common :refer :all] [puppetlabs.trapperkeeper.testutils.bootstrap :refer [with-app-with-empty-config with-app-with-config]] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [schema.core :as schema] [schema.test :as schema-test] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (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 test-websocket-service [[:WebroutingService add-websocket-handler]] (init [this context] (log/info "setting up webrouting websockets") (let [handlers {:on-connect (fn [ws] (ws-session/send! ws "heyo"))}] (add-websocket-handler this handlers)) context)) (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"} :puppetlabs.trapperkeeper.services.webrouting.webrouting-service-test/test-websocket-service "/baz"}}) (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 (testing "Other services can successfully use webrouting service" (with-app-with-config app [jetty9-service webrouting-service test-service test-websocket-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!"))) (let [message (promise) websocket (ws-client/connect "ws://localhost:8080/baz" :on-receive (fn [text] (deliver message text)))] (is (= @message "heyo")) (ws-client/close websocket)))) (testing "Error occurs when specifying service that does not exist in config file" (with-app-with-config app [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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))))))) trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver/000077500000000000000000000000001366056265300322375ustar00rootroot00000000000000jetty9_config_test.clj000066400000000000000000000512151366056265300364720ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-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.jetty9-config :refer :all] [puppetlabs.trapperkeeper.testutils.logging :refer [with-test-logging]] [puppetlabs.trapperkeeper.services.webserver.jetty9-core :as jetty9] [puppetlabs.trapperkeeper.services.webserver.jetty9-service :refer [jetty9-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 :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 :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"))) (deftest test-advanced-scripting-config (testing "Verify that we can use scripting to handle advanced configuration scenarios" (let [config {:webserver {:port 9000 :host "localhost" :post-config-script (str "import org.eclipse.jetty.server.ServerConnector;" "ServerConnector c = (ServerConnector)(server.getConnectors()[0]);\n" "c.setPort(10000);")}}] (with-test-logging (with-app-with-config app [jetty9-service] 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 body})] (testing "A warning is logged when using post-config-script" (is (logged? #"The 'post-config-script' setting is for advanced use" :warn))) (testing "scripted changes are executed properly" (add-ring-handler ring-handler path) (let [response (http-get (format "http://localhost:10000/%s" path))] (is (= (:status response) 200)) (is (= (:body response) body))))))))) (testing "Server fails to start with bad post-config-script" (let [base-config {:port 9000 :host "localhost"}] (testing "Throws an error if the script can't be compiled." (is (thrown-with-msg? IllegalArgumentException #"Invalid script string in webserver 'post-config-script' configuration" (let [context (jetty9/initialize-context)] (with-test-logging (try (jetty9/start-webserver! context (merge base-config {:post-config-script (str "AHAHHHGHAHAHAHEASD! OMG!")})) (finally (jetty9/shutdown context)))))))) (testing "Throws an error if the script can't be executed." (is (thrown-with-msg? IllegalArgumentException #"Invalid script string in webserver 'post-config-script' configuration" (let [context (jetty9/initialize-context)] (with-test-logging (try (jetty9/start-webserver! context (merge base-config {:post-config-script (str "Object x = null; x.toString();")})) (finally (jetty9/shutdown context))))))))))) jetty9_core_test.clj000066400000000000000000000643661366056265300361700ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-core-test (:import (org.eclipse.jetty.server.handler 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.jetty9-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.jetty9-default-config-test :refer [get-server-thread-pool-queue]] [puppetlabs.trapperkeeper.services.webserver.jetty9-service :refer [jetty9-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] [puppetlabs.trapperkeeper.testutils.logging :as tk-log-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 (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 jmx (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 [jetty9-service] config)))) (deftest override-webserver-settings!-tests (let [default-state {:mbean-container nil :overrides-read-by-webserver false :overrides nil :endpoints {} :ssl-context-factory nil} webserver-context (fn [state] {:handlers (ContextHandlerCollection.) :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 (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 (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 (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 (tk-log-testutils/with-test-logging (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 (tk-log-testutils/with-test-logging (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 (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 [jetty9-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 (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))) (is (= "" (: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)))))))) jetty9_default_config_test.clj000066400000000000000000000211471366056265300401770ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-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.jetty9-service :refer [jetty9-service]] [puppetlabs.trapperkeeper.app :refer [get-service]] [puppetlabs.trapperkeeper.services :refer [service-context]] [puppetlabs.trapperkeeper.services.webserver.jetty9-core :as core] [puppetlabs.trapperkeeper.testutils.webserver :as testutils] [puppetlabs.trapperkeeper.testutils.logging :as tk-log-testutils]) (: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-app-with-config app [jetty9-service] {:webserver {:host "localhost" :port 8080}} (let [s (get-service app :WebserverService) server-context (get-in (service-context s) [:jetty9-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-9.4.1.v20170120/jetty-util/src/main/java/org/eclipse/jetty/util/component/AbstractLifeCycle.java#L48 (is (= 30000 (.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)) jetty9_service_handlers_test.clj000066400000000000000000000651321366056265300405500ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-service-handlers-test (:import (servlet SimpleServlet) (javax.servlet ServletContextListener) (java.nio.file Paths Files) (java.nio.file.attribute FileAttribute) (javax.servlet.http HttpServlet HttpServletRequest HttpServletResponse)) (:require [clojure.test :refer :all] [gniazdo.core :as ws-client] [puppetlabs.experimental.websockets.client :as ws-session] [puppetlabs.trapperkeeper.services.webserver.jetty9-service :refer :all] [puppetlabs.trapperkeeper.testutils.webserver.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]] [schema.test :as schema-test] [clojure.tools.logging :as log] [puppetlabs.trapperkeeper.testutils.webserver :as testutils])) (use-fixtures :once schema-test/validate-schemas testutils/assert-clean-shutdown) (deftest static-content-test (testing "static content context" (with-app-with-config app [jetty9-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 [jetty9-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 [jetty9-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) 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 (= (:body response) body))))))) (deftest add-context-handler-symlinks-test (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 [jetty9-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 [jetty9-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 (testing "request to servlet over http succeeds" (with-app-with-config app [jetty9-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)] (add-servlet-handler servlet path) (let [response (http-get (str "http://localhost:8080" path))] (is (= (:status response) 200)) (is (= (:body response) body)))))) (testing "request to servlet over http succeeds with add-servlet-handler-to" (with-app-with-config app [jetty9-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)] (add-servlet-handler servlet path {:server-id :foo}) (let [response (http-get (str "http://localhost:8085" path))] (is (= (:status response) 200)) (is (= (:body response) body)))))) (testing "request to servlet initialized with empty param succeeds" (with-app-with-config app [jetty9-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)] (add-servlet-handler servlet path {:servlet-init-params {}}) (let [response (http-get (str "http://localhost:8080" path))] (is (= (:status response) 200)) (is (= (:body response) body)))))) (testing "request to servlet initialized with non-empty params succeeds" (with-app-with-config app [jetty9-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)] (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 (= (:body response) init-param-one))) (let [response (http-get (str "http://localhost:8080" path "/init-param-two"))] (is (= (:status response) 200)) (is (= (:body response) init-param-two))))))) (deftest websocket-test (testing "Websocket handlers" (with-app-with-config app [jetty9-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-websocket-handler (partial add-websocket-handler s) path "/test" connected (atom 0) server-messages (atom []) server-binary-messages (atom []) client-messages (atom []) client-binary-messages (atom []) client-request-path (atom "") client-remote-addr (atom "") client-is-ssl (atom nil) closed-request-path (atom "") binary-client-message (promise) closed (promise) handlers {:on-connect (fn [ws] (ws-session/send! ws "Hello client!") (swap! connected inc) (reset! client-request-path (ws-session/request-path ws)) (reset! client-remote-addr (.. (ws-session/remote-addr ws) (toString))) (reset! client-is-ssl (ws-session/ssl? ws))) :on-text (fn [ws text] (ws-session/send! ws (str "You said: " text)) (swap! server-messages conj text)) :on-bytes (fn [ws bytes offset len] (let [as-vec (vec bytes)] (ws-session/send! ws (byte-array (reverse as-vec))) (swap! server-binary-messages conj as-vec))) :on-error (fn [ws error]) ;; TODO - Add test for on-error behaviour :on-close (fn [ws code reason] (swap! connected dec) (reset! closed-request-path (ws-session/request-path ws)) (deliver closed true))}] (add-websocket-handler handlers path) (let [socket (ws-client/connect (str "ws://localhost:8080" path "/foo") :on-receive (fn [text] (swap! client-messages conj text)) :on-binary (fn [bytes offset len] (let [as-vec (vec bytes)] (swap! client-binary-messages conj as-vec) (deliver binary-client-message true))))] (ws-client/send-msg socket "Hello websocket handler") (ws-client/send-msg socket "You look dandy") (ws-client/send-msg socket (byte-array [2 1 2 3 3])) (deref binary-client-message) (is (= @connected 1)) (is (= @client-request-path "/foo")) (is (re-matches #"/127\.0\.0\.1:\d+" @client-remote-addr)) (is (= @client-is-ssl false)) (ws-client/close socket) (deref closed) (is (= @closed-request-path "/foo")) (is (= @connected 0)) (is (= @server-binary-messages [[2 1 2 3 3]])) (is (= @client-binary-messages [[3 3 2 1 2]])) (is (= @client-messages ["Hello client!" "You said: Hello websocket handler" "You said: You look dandy"])) (is (= @server-messages ["Hello websocket handler" "You look dandy"])))))) (testing "can close without supplying a reason" (with-app-with-config app [jetty9-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-websocket-handler (partial add-websocket-handler s) path "/test" closed (promise) handlers {:on-connect (fn [ws] (ws-session/close! ws))}] (add-websocket-handler handlers path) (let [socket (ws-client/connect (str "ws://localhost:8080" path) :on-close (fn [code reason] (deliver closed code)))] ;; 1000 is for normal closure https://tools.ietf.org/html/rfc6455#section-7.4.1 (is (= 1000 @closed)))))) (testing "can close with reason" (with-app-with-config app [jetty9-service] jetty-plaintext-config (let [s (get-service app :WebserverService) add-websocket-handler (partial add-websocket-handler s) path "/test" closed (promise) handlers {:on-connect (fn [ws] (ws-session/close! ws 4000 "Bye"))}] (add-websocket-handler handlers path) (let [socket (ws-client/connect (str "ws://localhost:8080" path) :on-close (fn [code reason] (deliver closed [code reason])))] (is (= [4000 "Bye"] @closed))))))) (deftest war-test (testing "WAR support" (with-app-with-config app [jetty9-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 [jetty9-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-app-with-config app [jetty9-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" path-websocket "/quux" 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) add-websocket-handler (partial add-websocket-handler s) ring-handler (fn [req] {:status 200 :body "Hi world"}) body "This is a test" servlet (SimpleServlet. body) context-listeners [(reify ServletContextListener (contextInitialized [this event] (doto (.addServlet (.getServletContext event) "simple" servlet) (.addMapping (into-array [path-servlet])))) (contextDestroyed [this event]))] war "helloWorld.war" websocket-handlers {:on-connect (fn [ws])} 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 {}) (add-websocket-handler websocket-handlers path-websocket) (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"}] "/quux" [{:type :websocket}]})))))) (testing "Log endpoints" (with-test-logging (with-app-with-config app [jetty9-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 (testing "redirects when no trailing slash is present are disabled by default" (with-app-with-config app [jetty9-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 [jetty9-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})] (is (= (:status response) 302)) (is (= (get-in response [:headers "location"]) "http://localhost:8080/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 (testing "when uri request normalization enabled for ring handler" (with-app-with-config app [jetty9-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}) (testing "uri with encoded characters is properly decoded" (let [response (http-get "http://localhost:8080/hello%2f%2f%77o%72l%64" {: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 (testing "when uri request normalization disabled for ring handler" (with-app-with-config app [jetty9-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}) (testing "uri with encoded characters is properly decoded" (let [response (http-get "http://localhost:8080/hello%2f%2f%77o%72l%64" {:as :text})] (is (= (:status response) 200)) (is (= (:body response) "/hello%2f%2f%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 resolved" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 200)) (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 (testing "when uri request normalization enabled for servlet" (with-app-with-config app [jetty9-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}) (testing "uri with encoded characters is properly decoded" (let [response (http-get "http://localhost:8080/hello%2f%2f%77o%72l%64" {: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 (testing "when uri request normalization disabled for servlet" (with-app-with-config app [jetty9-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}) (testing "uri with encoded characters is not decoded" (let [response (http-get "http://localhost:8080/hello%2f%2f%77o%72l%64" {:as :text})] (is (= (:status response) 200)) (is (= (:body response) "/hello%2f%2f%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 resolved" (let [response (http-get "http://localhost:8080/hello/world/%2E%2E/cleveland" {:as :text})] (is (= (:status response) 200)) (is (= (:body response) "/hello/world/%2E%2E/cleveland")))))))) jetty9_service_override_settings_test.clj000066400000000000000000000302041366056265300424770ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-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.jetty9-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 [jetty9-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 [jetty9-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-app-with-config app [jetty9-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-app-with-config app [jetty9-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-app-with-config app [jetty9-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.")))))jetty9_service_proxy_test.clj000066400000000000000000001044031366056265300401240ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-service-proxy-test (:import [java.net URI]) (:require [clojure.test :refer :all] [puppetlabs.trapperkeeper.services.webserver.jetty9-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]] [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!"} "/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!"} "/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!"} "/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-app-with-config proxy-target-app# [jetty9-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# [jetty9-service proxy-service#] {:webserver ~proxy} ~@body)) (with-app-with-config proxy-app# [jetty9-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 [proxy-req req] (.header proxy-req "x-fancy-proxy-header" "!!!")) (defn failure-callback-fn [req resp proxy-resp failure] (.setStatus resp 500) (.print (.getWriter resp) (str "Proxying failed: " (.getMessage failure)))) (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 123456789 ; illegal port number :path "/hello"} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 502)) (is (= (:body response) ""))))) (testing "proxying failure - custom 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 123456789 ; illegal port number :path "/hello"} :proxy-opts {:failure-callback-fn failure-callback-fn} :ring-handler proxy-ring-handler} (let [response (http-get "http://localhost:10000/hello-proxy/world")] (is (= (:status response) 500)) (is (= (:body response) "Proxying failed: port out of range:123456789"))))) (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)] (is (= 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)))))))) jetty9_service_test.clj000066400000000000000000001243171366056265300366710ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.jetty9-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.jetty9-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.jetty9-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 [jetty9-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 [jetty9-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 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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 jetty9-service] jetty-plaintext-config)) (defn boot-service-and-jetty-with-multiserver-config [service] (tk-core/boot-services-with-config [service jetty9-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) (:jetty9-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 [jetty9-service] jetty-plaintext-config)] (try (let [second-app (tk-core/boot-services-with-config [jetty9-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 [jetty9-service] jetty-plaintext-config) context-list (-> (tk-app/get-service app :WebserverService) (tk-services/service-context) (:jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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))))) (deftest request-logging-test (with-app-with-config app [jetty9-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 8" (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 "jetty9 webservers shut down gracefully by default" (with-app-with-config app [jetty9-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})] @in-request-handler (tk-app/stop app) (is (= (:status @response) 200)) (is (= (:body @response) "Hello, World!"))))))) (testing "jetty9's stop timeout can be changed from config" (with-app-with-config app [jetty9-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 ; [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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 [jetty9-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"]})) )] (if (SSLUtils/isFIPS) (is (thrown? IllegalArgumentException (test-fn))) (is (thrown? SSLException (test-fn))))))) (testing "SSLv3 is not supported even when configured" (tk-log-testutils/with-test-logging (with-app-with-config app [jetty9-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"]})) )] (if (SSLUtils/isFIPS) (is (thrown? IllegalArgumentException (test-fn))) (is (thrown? SSLException (test-fn))))))))) normalized_uri_helpers_test.clj000066400000000000000000000153651366056265300404700ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/services/webserver(ns puppetlabs.trapperkeeper.services.webserver.normalized-uri-helpers-test (:import (javax.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") ;; These are explicitly handled by Jetty as of 9.4.23 (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"))))) trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/testutils/000077500000000000000000000000001366056265300304505ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/testutils/webrouting/000077500000000000000000000000001366056265300326355ustar00rootroot00000000000000common.clj000066400000000000000000000013151366056265300345400ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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}) trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/testutils/webserver.clj000066400000000000000000000065721366056265300331600ustar00rootroot00000000000000(ns puppetlabs.trapperkeeper.testutils.webserver (:require [puppetlabs.trapperkeeper.services.webserver.jetty9-core :as jetty9] [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# (jetty9/start-webserver! (jetty9/initialize-context) (assoc ~config :port 0)) _# (jetty9/add-ring-handler srv# ~app "/" true false) ~port-var (-> (:server srv#) (.getConnectors) (first) (.getLocalPort))] (try ~@body (finally (jetty9/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))))) trapperkeeper-webserver-jetty9-4.1.0/test/clj/puppetlabs/trapperkeeper/testutils/webserver/000077500000000000000000000000001366056265300324545ustar00rootroot00000000000000common.clj000066400000000000000000000050151366056265300343600ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/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)))))) trapperkeeper-webserver-jetty9-4.1.0/test/java/000077500000000000000000000000001366056265300215315ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/java/appender/000077500000000000000000000000001366056265300233275ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/java/appender/TestListAppender.java000066400000000000000000000014511366056265300274250ustar00rootroot00000000000000package appender; import ch.qos.logback.access.PatternLayout; import ch.qos.logback.access.PatternLayoutEncoder; import ch.qos.logback.access.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; 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; } } trapperkeeper-webserver-jetty9-4.1.0/test/java/servlet/000077500000000000000000000000001366056265300232155ustar00rootroot00000000000000trapperkeeper-webserver-jetty9-4.1.0/test/java/servlet/SimpleServlet.java000066400000000000000000000021131366056265300266530ustar00rootroot00000000000000package servlet; import java.io.IOException; import javax.servlet.ServletConfig; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; public class SimpleServlet extends HttpServlet { private String body; private ServletConfig config; public SimpleServlet(String body) { this.body = body; this.config = null; } @Override public void init(final ServletConfig config) throws ServletException { this.config = config; } @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html"); response.setStatus(HttpServletResponse.SC_OK); String pathInfo = request.getPathInfo(); if (pathInfo != null && pathInfo.length() > 1 && pathInfo.charAt(0) == '/' && config != null) { response.getWriter().print(config.getInitParameter(pathInfo.substring(1))); } else { response.getWriter().print(body); } } }