From 7a44cf6014f2fd334f11f5cb32d9dd7775cfca63 Mon Sep 17 00:00:00 2001 From: Nick Couchman Date: Wed, 14 Feb 2018 13:26:08 -0500 Subject: [PATCH 01/12] GUACAMOLE-103: Implementation of SAML authentication extension, using OpenID as a template. --- extensions/guacamole-auth-saml/.gitignore | 3 + extensions/guacamole-auth-saml/pom.xml | 181 ++++++++++++ .../guacamole-auth-saml/src/licenses/LICENSE | 257 ++++++++++++++++++ .../guacamole-auth-saml/src/licenses/NOTICE | 5 + .../src/licenses/bundled/README | 4 + .../licenses/bundled/aopalliance-1.0/LICENSE | 4 + .../src/licenses/bundled/guice-3.0/COPYING | 202 ++++++++++++++ .../licenses/bundled/java-saml-2.2.0/LICENSE | 22 ++ .../bundled/javax.inject-1/LICENSE-2.0.txt | 202 ++++++++++++++ .../src/main/assembly/dist.xml | 53 ++++ .../saml/AuthenticationProviderService.java | 203 ++++++++++++++ .../auth/saml/SAMLAuthenticationProvider.java | 80 ++++++ .../SAMLAuthenticationProviderModule.java | 80 ++++++ .../SAMLAuthenticationProviderResource.java | 81 ++++++ .../auth/saml/conf/ConfigurationService.java | 233 ++++++++++++++++ .../auth/saml/form/SAMLRedirectField.java | 66 +++++ .../auth/saml/user/SAMLAuthenticatedUser.java | 71 +++++ .../src/main/resources/guac-manifest.json | 16 ++ .../src/main/resources/license.txt | 18 ++ .../src/main/resources/translations/en.json | 12 + pom.xml | 1 + 21 files changed, 1794 insertions(+) create mode 100644 extensions/guacamole-auth-saml/.gitignore create mode 100644 extensions/guacamole-auth-saml/pom.xml create mode 100644 extensions/guacamole-auth-saml/src/licenses/LICENSE create mode 100644 extensions/guacamole-auth-saml/src/licenses/NOTICE create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/README create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/aopalliance-1.0/LICENSE create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/guice-3.0/COPYING create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.2.0/LICENSE create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt create mode 100644 extensions/guacamole-auth-saml/src/main/assembly/dist.xml create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java create mode 100644 extensions/guacamole-auth-saml/src/main/resources/guac-manifest.json create mode 100644 extensions/guacamole-auth-saml/src/main/resources/license.txt create mode 100644 extensions/guacamole-auth-saml/src/main/resources/translations/en.json diff --git a/extensions/guacamole-auth-saml/.gitignore b/extensions/guacamole-auth-saml/.gitignore new file mode 100644 index 000000000..30eb48707 --- /dev/null +++ b/extensions/guacamole-auth-saml/.gitignore @@ -0,0 +1,3 @@ +*~ +target/ +src/main/resources/generated/ diff --git a/extensions/guacamole-auth-saml/pom.xml b/extensions/guacamole-auth-saml/pom.xml new file mode 100644 index 000000000..5029d85f9 --- /dev/null +++ b/extensions/guacamole-auth-saml/pom.xml @@ -0,0 +1,181 @@ + + + + + 4.0.0 + org.apache.guacamole + guacamole-auth-saml + jar + 1.2.0 + guacamole-auth-saml + http://guacamole.apache.org/ + + + UTF-8 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.8 + 1.8 + + -Xlint:all + -Werror + + true + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + unpack-dependencies + prepare-package + + unpack-dependencies + + + runtime + ${project.build.directory}/classes + META-INF/*.SF,META-INF/*.DSA + + + + + + + + maven-assembly-plugin + 2.5.3 + + ${project.artifactId}-${project.version} + false + + src/main/assembly/dist.xml + + + + + make-dist-archive + package + + single + + + + + + + + org.apache.rat + apache-rat-plugin + 0.12 + + + + **/*.json + src/licenses/**/* + src/main/resources/templates/*.html + + + + + + + validate + validate + + check + + + + + + + + + + + + + + org.apache.guacamole + guacamole-ext + 1.2.0 + provided + + + + + com.google.inject + guice + 3.0 + + + com.google.inject.extensions + guice-multibindings + 3.0 + + + + + javax.servlet + servlet-api + 2.5 + provided + + + + + com.sun.jersey + jersey-server + 1.17.1 + + + + + com.onelogin + java-saml + 2.5.0 + + + org.slf4j + slf4j-api + + + + + + + diff --git a/extensions/guacamole-auth-saml/src/licenses/LICENSE b/extensions/guacamole-auth-saml/src/licenses/LICENSE new file mode 100644 index 000000000..77bf5f6c4 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/LICENSE @@ -0,0 +1,257 @@ + + Apache 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. + + +============================================================================== + +APACHE GUACAMOLE SUBCOMPONENTS + +Apache Guacamole includes a number of subcomponents with separate copyright +notices and license terms. Your use of these subcomponents is subject to the +terms and conditions of the following licenses. + + +AOP Alliance (http://aopalliance.sourceforge.net/) +-------------------------------------------------- + + Version: 1.0 + From: 'AOP Alliance' (http://aopalliance.sourceforge.net/members.html) + License(s): + Public Domain (bundled/aopalliance-1.0/LICENSE) + + +Google Guice (https://github.com/google/guice) +---------------------------------------------- + + Version: 3.0 + From: 'Google Inc.' (http://www.google.com/) + License(s): + Apache v2.0 (bundled/guice-3.0/COPYING) + + +jose.4.j (https://bitbucket.org/b_c/jose4j/) +-------------------------------------------- + + Version: 0.5.5 + From: 'Brian Campbell' (https://bitbucket.org/b_c/) + License(s): + Apache v2.0 (bundled/jose4j-0.5.5/LICENSE) + + +JSR-330 / Dependency Injection for Java (http://code.google.com/p/atinject/) +---------------------------------------------------------------------------- + + Version: 1 + From: 'JSR-330 Expert Group' (https://jcp.org/en/jsr/detail?id=330) + License(s): + Apache v2.0 (bundled/javax.inject-1/LICENSE-2.0.txt) + + +Onelogin Java SAML Client (https://github.com/onelogin/java-saml) +------------------------------------------------------------------------ + + Version: 2.2.0 + From: 'OneLogin' (https://www.onelogin.com) + License(s): + MIT License (bundled/java-saml-2.2.0/LICENSE) + diff --git a/extensions/guacamole-auth-saml/src/licenses/NOTICE b/extensions/guacamole-auth-saml/src/licenses/NOTICE new file mode 100644 index 000000000..c5fc0d3af --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/NOTICE @@ -0,0 +1,5 @@ +Apache Guacamole +Copyright 2020 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/README b/extensions/guacamole-auth-saml/src/licenses/bundled/README new file mode 100644 index 000000000..47ba19db0 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/README @@ -0,0 +1,4 @@ +Apache Guacamole includes a number of subcomponents with separate copyright +notices and license terms. Your use of these subcomponents is subject to the +terms and conditions of their respective licenses, included within this +directory for reference. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/aopalliance-1.0/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/aopalliance-1.0/LICENSE new file mode 100644 index 000000000..8e0e3786b --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/aopalliance-1.0/LICENSE @@ -0,0 +1,4 @@ +From http://aopalliance.sourceforge.net/: + + LICENCE: all the source code provided by AOP Alliance is Public Domain. + diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/guice-3.0/COPYING b/extensions/guacamole-auth-saml/src/licenses/bundled/guice-3.0/COPYING new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/guice-3.0/COPYING @@ -0,0 +1,202 @@ + + Apache 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. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.2.0/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.2.0/LICENSE new file mode 100644 index 000000000..578413f8e --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.2.0/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2010-2016 OneLogin, Inc. + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt b/extensions/guacamole-auth-saml/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt @@ -0,0 +1,202 @@ + + Apache 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. diff --git a/extensions/guacamole-auth-saml/src/main/assembly/dist.xml b/extensions/guacamole-auth-saml/src/main/assembly/dist.xml new file mode 100644 index 000000000..b89fd534c --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/assembly/dist.xml @@ -0,0 +1,53 @@ + + + + + dist + ${project.artifactId}-${project.version} + + + + tar.gz + + + + + + + + + src/licenses + + + + + target + + + *.jar + + + + + + diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java new file mode 100644 index 000000000..db4e08201 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -0,0 +1,203 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml; + +import com.google.inject.Inject; +import com.google.inject.Provider; +import com.onelogin.saml2.authn.AuthnRequest; +import com.onelogin.saml2.authn.SamlResponse; +import com.onelogin.saml2.exception.SettingsException; +import com.onelogin.saml2.exception.ValidationError; +import com.onelogin.saml2.http.HttpRequest; +import com.onelogin.saml2.servlet.ServletUtils; +import com.onelogin.saml2.settings.Saml2Settings; +import com.onelogin.saml2.util.Util; +import java.io.IOException; +import java.util.Arrays; +import javax.servlet.http.HttpServletRequest; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathExpressionException; +import org.apache.guacamole.auth.saml.conf.ConfigurationService; +import org.apache.guacamole.auth.saml.form.SAMLRedirectField; +import org.apache.guacamole.auth.saml.user.SAMLAuthenticatedUser; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.form.Field; +import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.net.auth.Credentials; +import org.apache.guacamole.net.auth.credentials.CredentialsInfo; +import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException; +import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; + +/** + * Class that provides services for use by the SAMLAuthenticationProvider class. + */ +public class AuthenticationProviderService { + + /** + * Logger for this class. + */ + private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class); + + /** + * Service for retrieving SAML configuration information. + */ + @Inject + private ConfigurationService confService; + + /** + * Provider for AuthenticatedUser objects. + */ + @Inject + private Provider authenticatedUserProvider; + + /** + * Returns an AuthenticatedUser representing the user authenticated by the + * given credentials. + * + * @param credentials + * The credentials to use for authentication. + * + * @return + * An AuthenticatedUser representing the user authenticated by the + * given credentials. + * + * @throws GuacamoleException + * If an error occurs while authenticating the user, or if access is + * denied. + */ + public AuthenticatedUser authenticateUser(Credentials credentials) + throws GuacamoleException { + + HttpServletRequest request = credentials.getRequest(); + + // Initialize and configure SAML client. + Saml2Settings samlSettings = confService.getSamlSettings(); + + if (request != null) { + + // Look for the SAML Response parameter. + String samlResponseParam = request.getParameter("SAMLResponse"); + + if (samlResponseParam != null) { + + // Convert the SAML response into the version needed for the client. + HttpRequest httpRequest = ServletUtils.makeHttpRequest(request); + try { + + // Generate the response object + SamlResponse samlResponse = new SamlResponse(samlSettings, httpRequest); + + if (!samlResponse.validateNumAssertions()) { + logger.warn("SAML response contained other than single assertion."); + logger.debug("validateNumAssertions returned false."); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + if (!samlResponse.validateTimestamps()) { + logger.warn("SAML response timestamps were invalid."); + logger.debug("validateTimestamps returned false."); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + + // Grab the username, and, if present, finish authentication. + String username = samlResponse.getNameId().toLowerCase(); + if (username != null) { + credentials.setUsername(username); + SAMLAuthenticatedUser authenticatedUser = authenticatedUserProvider.get(); + authenticatedUser.init(username, credentials); + return authenticatedUser; + } + } + + // Errors are logged and result in a normal username/password login box. + catch (IOException e) { + logger.warn("Error during I/O while parsing SAML response: {}", e.getMessage()); + logger.debug("Received IOException when trying to parse SAML response.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + catch (ParserConfigurationException e) { + logger.warn("Error configuring XML parser: {}", e.getMessage()); + logger.debug("Received ParserConfigurationException when trying to parse SAML response.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + catch (SAXException e) { + logger.warn("Bad XML when parsing SAML response: {}", e.getMessage()); + logger.debug("Received SAXException while parsing SAML response.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + catch (SettingsException e) { + logger.warn("Error with SAML settings while parsing response: {}", e.getMessage()); + logger.debug("Received SettingsException while parsing SAML response.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + catch (ValidationError e) { + logger.warn("Error validating SAML response: {}", e.getMessage()); + logger.debug("Received ValidationError while parsing SAML response.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + catch (XPathExpressionException e) { + logger.warn("Problem with XML parsing response: {}", e.getMessage()); + logger.debug("Received XPathExpressionException while processing SAML response.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + catch (Exception e) { + logger.warn("Exception while getting name from SAML response: {}", e.getMessage()); + logger.debug("Received Exception while retrieving name from SAML response.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + } + } + + // No SAML Response is present, so generate a request. + AuthnRequest samlReq = new AuthnRequest(samlSettings); + String reqString; + try { + reqString = samlSettings.getIdpSingleSignOnServiceUrl() + "?SAMLRequest=" + + Util.urlEncoder(samlReq.getEncodedAuthnRequest()); + } + catch (IOException e) { + logger.error("Error encoding authentication request to string: {}", e.getMessage()); + logger.debug("Got IOException encoding authentication request.", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } + + // Redirect to SAML Identity Provider (IdP) + throw new GuacamoleInsufficientCredentialsException("Redirecting to SAML IdP.", + new CredentialsInfo(Arrays.asList(new Field[] { + new SAMLRedirectField(reqString) + })) + ); + + + } + +} diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java new file mode 100644 index 000000000..997922684 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml; + +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.net.auth.AbstractAuthenticationProvider; +import org.apache.guacamole.net.auth.Credentials; + +/** + * Class when provides authentication for the Guacamole Client against a + * SAML SSO Identity Provider (IdP). This module does not provide any + * storage for connection information, and must be layered with other + * modules in order to retrieve connections. + */ +public class SAMLAuthenticationProvider extends AbstractAuthenticationProvider { + + /** + * Injector which will manage the object graph of this authentication + * provider. + */ + private final Injector injector; + + /** + * Creates a new SAMLAuthenticationProvider that authenticates users + * against a SAML IdP. + * + * @throws GuacamoleException + * If a required property is missing, or an error occurs while parsing + * a property. + */ + public SAMLAuthenticationProvider() throws GuacamoleException { + + // Set up Guice injector. + injector = Guice.createInjector( + new SAMLAuthenticationProviderModule(this) + ); + + } + + @Override + public String getIdentifier() { + return "saml"; + } + + @Override + public Object getResource() throws GuacamoleException { + return injector.getInstance(SAMLAuthenticationProviderResource.class); + } + + @Override + public AuthenticatedUser authenticateUser(Credentials credentials) + throws GuacamoleException { + + // Attempt to authenticate user with given credentials + AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); + return authProviderService.authenticateUser(credentials); + + } + +} diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java new file mode 100644 index 000000000..9bd5cf20d --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml; + +import com.google.inject.AbstractModule; +import org.apache.guacamole.auth.saml.conf.ConfigurationService; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.environment.LocalEnvironment; +import org.apache.guacamole.net.auth.AuthenticationProvider; + +/** + * Guice module which configures SAML-specific injections. + */ +public class SAMLAuthenticationProviderModule extends AbstractModule { + + /** + * Guacamole server environment. + */ + private final Environment environment; + + /** + * A reference to the SAMLAuthenticationProvider on behalf of which this + * module has configured injection. + */ + private final AuthenticationProvider authProvider; + + /** + * Creates a new SAML authentication provider module which configures + * injection for the SAMLAuthenticationProvider. + * + * @param authProvider + * The AuthenticationProvider for which injection is being configured. + * + * @throws GuacamoleException + * If an error occurs while retrieving the Guacamole server + * environment. + */ + public SAMLAuthenticationProviderModule(AuthenticationProvider authProvider) + throws GuacamoleException { + + // Get local environment + this.environment = new LocalEnvironment(); + + // Store associated auth provider + this.authProvider = authProvider; + + } + + @Override + protected void configure() { + + // Bind core implementations of guacamole-ext classes + bind(AuthenticationProvider.class).toInstance(authProvider); + bind(Environment.class).toInstance(environment); + + // Bind saml-specific services + bind(ConfigurationService.class); + bind(SAMLAuthenticationProviderResource.class); + + } + +} diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java new file mode 100644 index 000000000..338e71491 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java @@ -0,0 +1,81 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml; + +import com.google.inject.Inject; +import com.onelogin.saml2.util.Util; +import java.net.URI; +import java.net.URISyntaxException; +import javax.ws.rs.core.Response; +import javax.ws.rs.FormParam; +import javax.ws.rs.Path; +import javax.ws.rs.POST; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleServerException; +import org.apache.guacamole.auth.saml.conf.ConfigurationService; + +/** + * A class that implements the REST API necessary for the + * SAML Idp to POST back its response to Guacamole. + */ +public class SAMLAuthenticationProviderResource { + + /** + * The configuration service for this module. + */ + @Inject + private ConfigurationService confService; + + /** + * A REST endpoint that is POSTed to by the SAML IdP + * with the results of the SAML SSO Authentication. + * + * @param samlResponse + * The encoded response returned by the SAML IdP. + * + * @return + * A HTTP Response that will redirect the user back to the + * Guacamole home page, with the SAMLResponse encoded in the + * return URL. + * + * @throws GuacamoleException + * If the Guacamole configuration cannot be read or an error occurs + * parsing a URI. + */ + @POST + @Path("callback") + public Response processSamlResponse(@FormParam("SAMLResponse") String samlResponse) + throws GuacamoleException { + + String guacBase = confService.getCallbackUrl().toString(); + try { + Response redirectHome = Response.seeOther( + new URI(guacBase + "?SAMLResponse=" + Util.urlEncoder(samlResponse))).build(); + return redirectHome; + } + catch (URISyntaxException e) { + throw new GuacamoleServerException("Error processing SAML response.", e); + } + + + + } + +} diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java new file mode 100644 index 000000000..faaec939c --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java @@ -0,0 +1,233 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml.conf; + +import com.google.inject.Inject; +import com.onelogin.saml2.settings.IdPMetadataParser; +import com.onelogin.saml2.settings.Saml2Settings; +import com.onelogin.saml2.settings.SettingsBuilder; +import com.onelogin.saml2.util.Constants; +import java.io.File; +import java.net.URI; +import java.util.HashMap; +import java.util.Map; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleServerException; +import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.properties.FileGuacamoleProperty; +import org.apache.guacamole.properties.URIGuacamoleProperty; + +/** + * Service for retrieving configuration information regarding the SAML + * authentication module. + */ +public class ConfigurationService { + + /** + * The file containing the XML Metadata associated with the SAML IdP. + */ + private static final FileGuacamoleProperty SAML_IDP_METADATA = + new FileGuacamoleProperty() { + + @Override + public String getName() { return "saml-idp-metadata"; } + + }; + + /** + * The URL of the SAML IdP. + */ + private static final URIGuacamoleProperty SAML_IDP_URL = + new URIGuacamoleProperty() { + + @Override + public String getName() { return "saml-idp-url"; } + + }; + + /** + * The URL identifier for this SAML client. + */ + private static final URIGuacamoleProperty SAML_ENTITY_ID = + new URIGuacamoleProperty() { + + @Override + public String getName() { return "saml-entity-id"; } + + }; + + /** + * The callback URL to use for SAML IdP, normally the base + * of the Guacamole install. + */ + private static final URIGuacamoleProperty SAML_CALLBACK_URL = + new URIGuacamoleProperty() { + + @Override + public String getName() { return "saml-callback-url"; } + + }; + + /** + * The single logout redirect URL. + */ + private static final URIGuacamoleProperty SAML_LOGOUT_URL = + new URIGuacamoleProperty() { + + @Override + public String getName() { return "saml-logout-url"; } + + }; + + /** + * The Guacamole server environment. + */ + @Inject + private Environment environment; + + /** + * Returns the URL to be used as the client ID which will be + * submitted to the SAML IdP as configured in + * guacamole.properties. + * + * @return + * The URL to be used as the client ID sent to the + * SAML IdP. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed, or if the + * property is missing. + */ + private URI getEntityId() throws GuacamoleException { + return environment.getRequiredProperty(SAML_ENTITY_ID); + } + + /** + * The file that contains the metadata that the SAML client should + * use to communicate with the SAML IdP. This is generated by the + * SAML IdP and should be uploaded to the system where the Guacamole + * client is running. + * + * @return + * The file containing the metadata used by the SAML client + * when it communicates with the SAML IdP. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed, or if the client + * metadata is missing. + */ + private File getIdpMetadata() throws GuacamoleException { + return environment.getProperty(SAML_IDP_METADATA); + } + + /** + * Retrieve the URL used to log in to the SAML IdP. + * + * @return + * The URL used to log in to the SAML IdP. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + private URI getIdpUrl() throws GuacamoleException { + return environment.getProperty(SAML_IDP_URL); + } + + /** + * The callback URL used for the SAML IdP to POST a response + * to upon completion of authentication, normally the base + * of the Guacamole install. + * + * @return + * The callback URL to be sent to the SAML IdP that will + * be POSTed to upon completion of SAML authentication. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed, or if the + * callback parameter is missing. + */ + public URI getCallbackUrl() throws GuacamoleException { + return environment.getRequiredProperty(SAML_CALLBACK_URL); + } + + /** + * Return the URL used to log out from the SAML IdP. + * + * @return + * The URL used to log out from the SAML IdP. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + private URI getLogoutUrl() throws GuacamoleException { + return environment.getProperty(SAML_LOGOUT_URL); + } + + /** + * Returns the collection of SAML settings used to + * initialize the client. + * + * @return + * The collection of SAML settings used to + * initialize the SAML client. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed or + * if parameters are missing. + */ + public Saml2Settings getSamlSettings() throws GuacamoleException { + + File idpMetadata = getIdpMetadata(); + Map samlMap; + if (idpMetadata != null) { + try { + samlMap = IdPMetadataParser.parseFileXML(idpMetadata.getAbsolutePath()); + } + catch (Exception e) { + throw new GuacamoleServerException( + "Could not parse SAML IdP Metadata file.", e); + } + } + + else { + samlMap = new HashMap<>(); + samlMap.put(SettingsBuilder.SP_ENTITYID_PROPERTY_KEY, + getEntityId().toString()); + samlMap.put(SettingsBuilder.SP_ASSERTION_CONSUMER_SERVICE_URL_PROPERTY_KEY, + getCallbackUrl().toString() + "/api/ext/saml/callback"); + samlMap.put(SettingsBuilder.IDP_ENTITYID_PROPERTY_KEY + , getIdpUrl().toString()); + samlMap.put(SettingsBuilder.IDP_SINGLE_SIGN_ON_SERVICE_URL_PROPERTY_KEY, + getIdpUrl().toString()); + samlMap.put(SettingsBuilder.IDP_SINGLE_SIGN_ON_SERVICE_BINDING_PROPERTY_KEY, + Constants.BINDING_HTTP_REDIRECT); + } + + SettingsBuilder samlBuilder = new SettingsBuilder(); + Saml2Settings samlSettings = samlBuilder.fromValues(samlMap).build(); + samlSettings.setDebug(true); + samlSettings.setCompressRequest(true); + samlSettings.setCompressResponse(true); + + return samlSettings; + } + + +} diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java new file mode 100644 index 000000000..f979b7805 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java @@ -0,0 +1,66 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml.form; + +import org.apache.guacamole.form.Field; + +/** + * Field definition which represents the data used to do redirects + * during SAML authentication. + */ +public class SAMLRedirectField extends Field { + + /** + * The name of the parameter containing the redirect. + */ + public static final String PARAMETER_NAME = "samlRedirect"; + + /** + * The encoded URI of the redirect. + */ + private final String samlRedirect; + + /** + * Creates a new field which facilitates redirection of the user + * during SAML SSO authentication. + * + * @param samlRedirect + * The URI to which the user should be redirected. + */ + public SAMLRedirectField(String samlRedirect) { + + // Init base field properties + super(PARAMETER_NAME, "GUAC_SAML_REDIRECT"); + + this.samlRedirect = samlRedirect; + + } + + /** + * Returns the URI of the redirect. + * + * @return + * The URI of the redirect. + */ + public String getSamlRedirect() { + return samlRedirect; + } + +} diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java new file mode 100644 index 000000000..fcc1a0446 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java @@ -0,0 +1,71 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml.user; + +import com.google.inject.Inject; +import org.apache.guacamole.net.auth.AbstractAuthenticatedUser; +import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.net.auth.Credentials; + +/** + * An SAML-specific implementation of AuthenticatedUser, associating a + * username and particular set of credentials with the SAML authentication + * provider. + */ +public class SAMLAuthenticatedUser extends AbstractAuthenticatedUser { + + /** + * Reference to the authentication provider associated with this + * authenticated user. + */ + @Inject + private AuthenticationProvider authProvider; + + /** + * The credentials provided when this user was authenticated. + */ + private Credentials credentials; + + /** + * Initializes this AuthenticatedUser using the given username and + * credentials. + * + * @param username + * The username of the user that was authenticated. + * + * @param credentials + * The credentials provided when this user was authenticated. + */ + public void init(String username, Credentials credentials) { + this.credentials = credentials; + setIdentifier(username); + } + + @Override + public AuthenticationProvider getAuthenticationProvider() { + return authProvider; + } + + @Override + public Credentials getCredentials() { + return credentials; + } + +} diff --git a/extensions/guacamole-auth-saml/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-saml/src/main/resources/guac-manifest.json new file mode 100644 index 000000000..bdb6d94c9 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/resources/guac-manifest.json @@ -0,0 +1,16 @@ +{ + + "guacamoleVersion" : "1.2.0", + + "name" : "SAML Authentication Extension", + "namespace" : "saml", + + "authProviders" : [ + "org.apache.guacamole.auth.saml.SAMLAuthenticationProvider" + ], + + "translations" : [ + "translations/en.json" + ] + +} diff --git a/extensions/guacamole-auth-saml/src/main/resources/license.txt b/extensions/guacamole-auth-saml/src/main/resources/license.txt new file mode 100644 index 000000000..042f3ce1f --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/resources/license.txt @@ -0,0 +1,18 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ diff --git a/extensions/guacamole-auth-saml/src/main/resources/translations/en.json b/extensions/guacamole-auth-saml/src/main/resources/translations/en.json new file mode 100644 index 000000000..3ba3a85c5 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/resources/translations/en.json @@ -0,0 +1,12 @@ +{ + + "DATA_SOURCE_SAML" : { + "NAME" : "SAML SSO Backend" + }, + + "LOGIN" : { + "FIELD_HEADER_SAML" : "", + "INFO_SAML_REDIRECT_PENDING" : "Please wait, redirecting for SAML authentication..." + } + +} diff --git a/pom.xml b/pom.xml index b90ef3a1e..84dbac6cd 100644 --- a/pom.xml +++ b/pom.xml @@ -56,6 +56,7 @@ extensions/guacamole-auth-ldap extensions/guacamole-auth-openid extensions/guacamole-auth-quickconnect + extensions/guacamole-auth-saml extensions/guacamole-auth-totp From 2a2172914d9fd8fab3393d455503e9faebcc6fa1 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Sun, 22 Mar 2020 20:33:24 -0400 Subject: [PATCH 02/12] GUACAMOLE-103: Move SAMLResponse processing to authentication service. --- extensions/guacamole-auth-saml/pom.xml | 7 +- .../saml/AuthenticationProviderService.java | 23 ++-- .../auth/saml/SAMLAuthenticationProvider.java | 3 +- .../SAMLAuthenticationProviderModule.java | 3 +- .../SAMLAuthenticationProviderResource.java | 101 +++++++++++++++--- .../guacamole/auth/saml/SAMLResponseMap.java | 80 ++++++++++++++ 6 files changed, 190 insertions(+), 27 deletions(-) create mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java diff --git a/extensions/guacamole-auth-saml/pom.xml b/extensions/guacamole-auth-saml/pom.xml index 5029d85f9..135ffacd5 100644 --- a/extensions/guacamole-auth-saml/pom.xml +++ b/extensions/guacamole-auth-saml/pom.xml @@ -158,9 +158,10 @@ - com.sun.jersey - jersey-server - 1.17.1 + javax.ws.rs + jsr311-api + 1.1.1 + provided diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index db4e08201..e819142d5 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -25,8 +25,6 @@ import com.onelogin.saml2.authn.AuthnRequest; import com.onelogin.saml2.authn.SamlResponse; import com.onelogin.saml2.exception.SettingsException; import com.onelogin.saml2.exception.ValidationError; -import com.onelogin.saml2.http.HttpRequest; -import com.onelogin.saml2.servlet.ServletUtils; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; import java.io.IOException; @@ -69,6 +67,12 @@ public class AuthenticationProviderService { */ @Inject private Provider authenticatedUserProvider; + + /** + * The map used to track active SAML responses. + */ + @Inject + private SAMLResponseMap samlResponseMap; /** * Returns an AuthenticatedUser representing the user authenticated by the @@ -87,7 +91,7 @@ public class AuthenticationProviderService { */ public AuthenticatedUser authenticateUser(Credentials credentials) throws GuacamoleException { - + HttpServletRequest request = credentials.getRequest(); // Initialize and configure SAML client. @@ -96,16 +100,18 @@ public class AuthenticationProviderService { if (request != null) { // Look for the SAML Response parameter. - String samlResponseParam = request.getParameter("SAMLResponse"); + String responseHash = Util.urlDecoder(request.getParameter("responseHash")); - if (samlResponseParam != null) { + if (responseHash != null) { - // Convert the SAML response into the version needed for the client. - HttpRequest httpRequest = ServletUtils.makeHttpRequest(request); try { // Generate the response object - SamlResponse samlResponse = new SamlResponse(samlSettings, httpRequest); + if (!samlResponseMap.hasSamlResponse(responseHash)) + throw new GuacamoleInvalidCredentialsException("Provided response has not found.", + CredentialsInfo.USERNAME_PASSWORD); + + SamlResponse samlResponse = samlResponseMap.getSamlResponse(responseHash); if (!samlResponse.validateNumAssertions()) { logger.warn("SAML response contained other than single assertion."); @@ -197,7 +203,6 @@ public class AuthenticationProviderService { })) ); - } } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java index 997922684..a51d1050d 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java @@ -72,7 +72,8 @@ public class SAMLAuthenticationProvider extends AbstractAuthenticationProvider { throws GuacamoleException { // Attempt to authenticate user with given credentials - AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class); + AuthenticationProviderService authProviderService = + injector.getInstance(AuthenticationProviderService.class); return authProviderService.authenticateUser(credentials); } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java index 9bd5cf20d..faa093550 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderModule.java @@ -71,9 +71,10 @@ public class SAMLAuthenticationProviderModule extends AbstractModule { bind(AuthenticationProvider.class).toInstance(authProvider); bind(Environment.class).toInstance(environment); - // Bind saml-specific services + // Bind SAML-specific services bind(ConfigurationService.class); bind(SAMLAuthenticationProviderResource.class); + bind(SAMLResponseMap.class); } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java index 338e71491..2dcdffaf0 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java @@ -20,16 +20,34 @@ package org.apache.guacamole.auth.saml; import com.google.inject.Inject; +import com.onelogin.saml2.authn.SamlResponse; +import com.onelogin.saml2.exception.SettingsException; +import com.onelogin.saml2.exception.ValidationError; +import com.onelogin.saml2.http.HttpRequest; +import com.onelogin.saml2.servlet.ServletUtils; +import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; +import java.io.IOException; import java.net.URI; import java.net.URISyntaxException; +import java.nio.charset.StandardCharsets; +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import javax.servlet.http.HttpServletRequest; import javax.ws.rs.core.Response; import javax.ws.rs.FormParam; import javax.ws.rs.Path; import javax.ws.rs.POST; +import javax.ws.rs.core.Context; +import javax.xml.bind.DatatypeConverter; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.xpath.XPathExpressionException; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.auth.saml.conf.ConfigurationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.xml.sax.SAXException; /** * A class that implements the REST API necessary for the @@ -37,19 +55,36 @@ import org.apache.guacamole.auth.saml.conf.ConfigurationService; */ public class SAMLAuthenticationProviderResource { + /** + * Logger for this class. + */ + private final Logger logger = + LoggerFactory.getLogger(SAMLAuthenticationProviderResource.class); + /** * The configuration service for this module. */ @Inject private ConfigurationService confService; + + /** + * The map used to track active responses. + */ + @Inject + private SAMLResponseMap samlResponseMap; /** * A REST endpoint that is POSTed to by the SAML IdP * with the results of the SAML SSO Authentication. * - * @param samlResponse + * @param samlResponseString * The encoded response returned by the SAML IdP. * + * @param consumedRequest + * The HttpServletRequest associated with the SAML response. The + * parameters of this request may not be accessible, as the request may + * have been fully consumed by JAX-RS. + * * @return * A HTTP Response that will redirect the user back to the * Guacamole home page, with the SAMLResponse encoded in the @@ -61,21 +96,61 @@ public class SAMLAuthenticationProviderResource { */ @POST @Path("callback") - public Response processSamlResponse(@FormParam("SAMLResponse") String samlResponse) + public Response processSamlResponse( + @FormParam("SAMLResponse") String samlResponseString, + @Context HttpServletRequest consumedRequest) throws GuacamoleException { - - String guacBase = confService.getCallbackUrl().toString(); - try { - Response redirectHome = Response.seeOther( - new URI(guacBase + "?SAMLResponse=" + Util.urlEncoder(samlResponse))).build(); - return redirectHome; - } - catch (URISyntaxException e) { - throw new GuacamoleServerException("Error processing SAML response.", e); - } - + String guacBase = confService.getCallbackUrl().toString(); + Saml2Settings samlSettings = confService.getSamlSettings(); + try { + HttpRequest request = ServletUtils + .makeHttpRequest(consumedRequest) + .addParameter("SAMLResponse", samlResponseString); + SamlResponse samlResponse = new SamlResponse(samlSettings, request); + + String responseHash = hashSamlResponse(samlResponseString); + samlResponseMap.putSamlResponse(responseHash, samlResponse); + return Response.seeOther(new URI(guacBase + + "?responseHash=" + + Util.urlEncoder(responseHash)) + ).build(); + } + catch (IOException + | NoSuchAlgorithmException + | ParserConfigurationException + | SAXException + | SettingsException + | URISyntaxException + | ValidationError + | XPathExpressionException e) { + throw new GuacamoleServerException(e); + } + + } + + /** + * This is a utility method designed to generate a SHA-256 has for the + * given string representation of the SAMLResponse, throwing an exception + * if, for some reason, the Java implementation in use doesn't support + * SHA-256, and returning a hex-formatted hash value. + * + * @param samlResponse + * The String representation of the SAML response. + * + * @return + * A hex-formatted string of the SHA-256 hash. + * + * @throws NoSuchAlgorithmException + * If Java does not support SHA-256. + */ + private String hashSamlResponse(String samlResponse) + throws NoSuchAlgorithmException { + + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + return DatatypeConverter.printHexBinary( + digest.digest(samlResponse.getBytes(StandardCharsets.UTF_8))); } } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java new file mode 100644 index 000000000..3a199045c --- /dev/null +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java @@ -0,0 +1,80 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you 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. + */ + +package org.apache.guacamole.auth.saml; + +import com.google.inject.Singleton; +import com.onelogin.saml2.authn.SamlResponse; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +/** + * A class that handles mapping of hashes to SAMLResponse objects. + */ +@Singleton +public class SAMLResponseMap { + + /** + * The internal data structure that holds a map of SHA-256 hashes to + * SAML responses. + */ + private final ConcurrentMap samlResponseMap = + new ConcurrentHashMap<>(); + + /** + * Retrieve the SamlResponse from the map that is represented by the + * provided hash, or null if no such object exists. + * + * @param hash + * The SHA-256 hash of the SamlResponse. + * + * @return + * The SamlResponse object matching the hash provided. + */ + protected SamlResponse getSamlResponse(String hash) { + return samlResponseMap.remove(hash); + } + + /** + * Place the provided mapping of hash to SamlResponse into the map. + * + * @param hash + * The hash that will be the lookup key for this SamlResponse. + * + * @param samlResponse + * The SamlResponse object. + */ + protected void putSamlResponse(String hash, SamlResponse samlResponse) { + samlResponseMap.put(hash, samlResponse); + } + + /** + * Return true if the provided hash key exists in the map, otherwise false. + * + * @param hash + * The hash key to look for in the map. + * + * @return + * true if the provided hash is present, otherwise false. + */ + protected boolean hasSamlResponse(String hash) { + return samlResponseMap.containsKey(hash); + } + +} From ddac552a721b1dfc6ca3017db8f4288c7f980df2 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 25 May 2020 09:02:30 -0400 Subject: [PATCH 03/12] GUACAMOLE-103: Add settings for controlling debug and compression. --- .../auth/saml/conf/ConfigurationService.java | 87 ++++++++++++++++++- 1 file changed, 84 insertions(+), 3 deletions(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java index faaec939c..b006a89a2 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java @@ -31,6 +31,7 @@ import java.util.Map; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.properties.BooleanGuacamoleProperty; import org.apache.guacamole.properties.FileGuacamoleProperty; import org.apache.guacamole.properties.URIGuacamoleProperty; @@ -95,6 +96,40 @@ public class ConfigurationService { public String getName() { return "saml-logout-url"; } }; + + /** + * Whether or not debugging should be enabled in the SAML library to help + * track down errors. + */ + private static final BooleanGuacamoleProperty SAML_DEBUG = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "saml-debug"; } + + }; + + /** + * Whether or not to enabled compression for the SAML request. + */ + private static final BooleanGuacamoleProperty SAML_COMPRESS_REQUEST = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "saml-compress-request"; } + + }; + + /** + * Whether or not to enabled compression for the SAML response. + */ + private static final BooleanGuacamoleProperty SAML_COMPRESS_RESPONSE = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "saml-compress-response"; } + + }; /** * The Guacamole server environment. @@ -179,6 +214,52 @@ public class ConfigurationService { private URI getLogoutUrl() throws GuacamoleException { return environment.getProperty(SAML_LOGOUT_URL); } + + /** + * Return true if SAML debugging should be enabled, otherwise false. The + * default is false. + * + * @return + * True if debugging should be enabled in the SAML library, otherwise + * false. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + private Boolean getDebug() throws GuacamoleException { + return environment.getProperty(SAML_DEBUG, false); + } + + /** + * Return true if compression should be enabled when sending the SAML + * request, otherwise false. The default is to enable compression. + * + * @return + * True if compression should be enabled when sending the SAML request, + * otherwise false. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + private Boolean getCompressRequest() throws GuacamoleException { + return environment.getProperty(SAML_COMPRESS_REQUEST, true); + } + + /** + * Return true if compression should be requested from the server when the + * SAML response is returned, otherwise false. The default is to request + * that the response be compressed. + * + * @return + * True if compression should be requested from the server for the SAML + * response. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + private Boolean getCompressResponse() throws GuacamoleException { + return environment.getProperty(SAML_COMPRESS_RESPONSE, true); + } /** * Returns the collection of SAML settings used to @@ -222,9 +303,9 @@ public class ConfigurationService { SettingsBuilder samlBuilder = new SettingsBuilder(); Saml2Settings samlSettings = samlBuilder.fromValues(samlMap).build(); - samlSettings.setDebug(true); - samlSettings.setCompressRequest(true); - samlSettings.setCompressResponse(true); + samlSettings.setDebug(getDebug()); + samlSettings.setCompressRequest(getCompressRequest()); + samlSettings.setCompressResponse(getCompressResponse()); return samlSettings; } From 129cd6ace57699c19343bd878d41dd33f7148f37 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 25 May 2020 09:07:47 -0400 Subject: [PATCH 04/12] GUACAMOLE-103: Remove unnecessary parameter decoding --- .../guacamole/auth/saml/AuthenticationProviderService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index e819142d5..656ef5f9a 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -100,7 +100,7 @@ public class AuthenticationProviderService { if (request != null) { // Look for the SAML Response parameter. - String responseHash = Util.urlDecoder(request.getParameter("responseHash")); + String responseHash = request.getParameter("responseHash"); if (responseHash != null) { From 2d1f49aae5304293939040c79aaf534945c5627b Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 25 May 2020 13:45:31 -0400 Subject: [PATCH 05/12] GUACAMOLE-103: Add option for enforcing strict SAML security. --- .../auth/saml/conf/ConfigurationService.java | 28 +++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java index b006a89a2..52324ce22 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java @@ -130,6 +130,17 @@ public class ConfigurationService { public String getName() { return "saml-compress-response"; } }; + + /** + * Whether or not to enforce strict SAML security during processing. + */ + private static final BooleanGuacamoleProperty SAML_STRICT = + new BooleanGuacamoleProperty() { + + @Override + public String getName() { return "saml-strict"; } + + }; /** * The Guacamole server environment. @@ -245,6 +256,22 @@ public class ConfigurationService { return environment.getProperty(SAML_COMPRESS_REQUEST, true); } + /** + * Returns whether or not the SAML login should enforce strict security + * controls. By default this is true, and should be set to true in any + * production environment. + * + * @return + * True if the SAML login should enforce strict security checks, + * otherwise false. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + private Boolean getStrict() throws GuacamoleException { + return environment.getProperty(SAML_STRICT, true); + } + /** * Return true if compression should be requested from the server when the * SAML response is returned, otherwise false. The default is to request @@ -303,6 +330,7 @@ public class ConfigurationService { SettingsBuilder samlBuilder = new SettingsBuilder(); Saml2Settings samlSettings = samlBuilder.fromValues(samlMap).build(); + samlSettings.setStrict(getStrict()); samlSettings.setDebug(getDebug()); samlSettings.setCompressRequest(getCompressRequest()); samlSettings.setCompressResponse(getCompressResponse()); From 1c9efb2a4486050ce2f416c1b3cc53e66dfdb916 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 25 May 2020 13:54:08 -0400 Subject: [PATCH 06/12] GUACAMOLE-103: Process SAML exceptions individually. --- .../SAMLAuthenticationProviderResource.java | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java index 2dcdffaf0..8ed52cd83 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java @@ -117,15 +117,29 @@ public class SAMLAuthenticationProviderResource { ).build(); } - catch (IOException - | NoSuchAlgorithmException - | ParserConfigurationException - | SAXException - | SettingsException - | URISyntaxException - | ValidationError - | XPathExpressionException e) { - throw new GuacamoleServerException(e); + catch (IOException e) { + throw new GuacamoleServerException("I/O exception processing SAML response.", e); + } + catch (NoSuchAlgorithmException e) { + throw new GuacamoleServerException("Unexpected missing SHA-256 support while generating SAML response hash.", e); + } + catch (ParserConfigurationException e) { + throw new GuacamoleServerException("Parser exception processing SAML response.", e); + } + catch (SAXException e) { + throw new GuacamoleServerException("SAX exception processing SAML response.", e); + } + catch (SettingsException e) { + throw new GuacamoleServerException("Settings exception processing SAML response.", e); + } + catch (URISyntaxException e) { + throw new GuacamoleServerException("URI exception process SAML response.", e); + } + catch (ValidationError e) { + throw new GuacamoleServerException("Exception validating SAML response.", e); + } + catch (XPathExpressionException e) { + throw new GuacamoleServerException("XML Xpath exception validating SAML response.", e); } } From 09429492e0dfdc6018c606a89d3943bde76f5dbb Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Mon, 25 May 2020 19:56:47 -0400 Subject: [PATCH 07/12] GUACAMOLE-103: Periodically clean SAMLResponseMap for expired responses. --- .../saml/AuthenticationProviderService.java | 40 +++++++++++++++-- .../guacamole/auth/saml/SAMLResponseMap.java | 43 +++++++++++++++++++ .../auth/saml/conf/ConfigurationService.java | 27 ++++++++++++ .../auth/saml/user/SAMLAuthenticatedUser.java | 38 +++++++++++++++- 4 files changed, 144 insertions(+), 4 deletions(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index 656ef5f9a..718a0c0f7 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -21,6 +21,7 @@ package org.apache.guacamole.auth.saml; import com.google.inject.Inject; import com.google.inject.Provider; +import com.onelogin.saml2.Auth; import com.onelogin.saml2.authn.AuthnRequest; import com.onelogin.saml2.authn.SamlResponse; import com.onelogin.saml2.exception.SettingsException; @@ -29,6 +30,11 @@ import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; @@ -129,9 +135,22 @@ public class AuthenticationProviderService { // Grab the username, and, if present, finish authentication. String username = samlResponse.getNameId().toLowerCase(); if (username != null) { + + // Retrieve any provided attributes + Map> attributes = + samlResponse.getAttributes(); + + // Back-port the username to the credentials credentials.setUsername(username); - SAMLAuthenticatedUser authenticatedUser = authenticatedUserProvider.get(); - authenticatedUser.init(username, credentials); + + // Configure the AuthenticatedUser and return it + SAMLAuthenticatedUser authenticatedUser = + authenticatedUserProvider.get(); + + authenticatedUser.init(username, credentials, + parseTokens(attributes), + new HashSet<>(attributes.get(confService.getGroupAttribute()))); + return authenticatedUser; } } @@ -199,10 +218,25 @@ public class AuthenticationProviderService { // Redirect to SAML Identity Provider (IdP) throw new GuacamoleInsufficientCredentialsException("Redirecting to SAML IdP.", new CredentialsInfo(Arrays.asList(new Field[] { - new SAMLRedirectField(reqString) + new RedirectField("samlRedirect", reqString, "LOGIN.REDIRECT_PENDING") })) ); } + + private Map parseTokens(Map> attributes) + throws GuacamoleException { + + Map tokens = new HashMap<>(); + for (Entry> entry : attributes.entrySet()) { + + List values = entry.getValue(); + tokens.put(entry.getKey(), values.get(0)); + + } + + return tokens; + + } } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java index 3a199045c..588811a99 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java @@ -21,8 +21,13 @@ package org.apache.guacamole.auth.saml; import com.google.inject.Singleton; import com.onelogin.saml2.authn.SamlResponse; +import com.onelogin.saml2.exception.ValidationError; +import java.util.Map.Entry; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; /** * A class that handles mapping of hashes to SAMLResponse objects. @@ -37,6 +42,21 @@ public class SAMLResponseMap { private final ConcurrentMap samlResponseMap = new ConcurrentHashMap<>(); + /** + * Executor service which runs the periodic cleanup task + */ + private final ScheduledExecutorService executor = + Executors.newScheduledThreadPool(1); + + /** + * Create a new instance of this response map and kick off the executor + * that schedules the response cleanup task to run every five minutes. + */ + public SAMLResponseMap() { + // Cleanup unclaimed responses every five minutes + executor.scheduleAtFixedRate(new SAMLResponseCleanupTask(), 5, 5, TimeUnit.MINUTES); + } + /** * Retrieve the SamlResponse from the map that is represented by the * provided hash, or null if no such object exists. @@ -77,4 +97,27 @@ public class SAMLResponseMap { return samlResponseMap.containsKey(hash); } + /** + * Task which runs every five minutes and cleans up any expired SAML + * responses that haven't been claimed and removed from the map. + */ + private class SAMLResponseCleanupTask implements Runnable { + + @Override + public void run() { + + // Loop through responses in map and remove ones that are no longer valid. + for (Entry entry : samlResponseMap.entrySet()) { + try { + entry.getValue().validateTimestamps(); + } + catch (ValidationError e) { + samlResponseMap.remove(entry.getKey()); + } + } + + } + + } + } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java index 52324ce22..e216ccbca 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java @@ -33,6 +33,7 @@ import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.BooleanGuacamoleProperty; import org.apache.guacamole.properties.FileGuacamoleProperty; +import org.apache.guacamole.properties.StringGuacamoleProperty; import org.apache.guacamole.properties.URIGuacamoleProperty; /** @@ -141,6 +142,18 @@ public class ConfigurationService { public String getName() { return "saml-strict"; } }; + + /** + * The property that defines what attribute the SAML provider will return + * that contains group membership for the authenticated user. + */ + private static final StringGuacamoleProperty SAML_GROUP_ATTRIBUTE = + new StringGuacamoleProperty() { + + @Override + public String getName() { return "saml-group-attribute"; } + + }; /** * The Guacamole server environment. @@ -287,6 +300,20 @@ public class ConfigurationService { private Boolean getCompressResponse() throws GuacamoleException { return environment.getProperty(SAML_COMPRESS_RESPONSE, true); } + + /** + * Return the name of the attribute that will be supplied by the identity + * provider that contains the groups of which this user is a member. + * + * @return + * The name of the attribute that contains the user groups. + * + * @throws GuacamoleException + * If guacamole.properties cannot be parsed. + */ + public String getGroupAttribute() throws GuacamoleException { + return environment.getProperty(SAML_GROUP_ATTRIBUTE, "groups"); + } /** * Returns the collection of SAML settings used to diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java index fcc1a0446..57c70a365 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java @@ -20,6 +20,8 @@ package org.apache.guacamole.auth.saml.user; import com.google.inject.Inject; +import java.util.Map; +import java.util.Set; import org.apache.guacamole.net.auth.AbstractAuthenticatedUser; import org.apache.guacamole.net.auth.AuthenticationProvider; import org.apache.guacamole.net.auth.Credentials; @@ -42,6 +44,16 @@ public class SAMLAuthenticatedUser extends AbstractAuthenticatedUser { * The credentials provided when this user was authenticated. */ private Credentials credentials; + + /** + * The effective groups of the authenticated user. + */ + private Set effectiveGroups; + + /** + * Tokens associated with the authenticated user. + */ + private Map tokens; /** * Initializes this AuthenticatedUser using the given username and @@ -52,11 +64,30 @@ public class SAMLAuthenticatedUser extends AbstractAuthenticatedUser { * * @param credentials * The credentials provided when this user was authenticated. + * + * @param tokens + * The tokens available from this authentication provider. + * + * @param effectiveGroups + * The groups of which this user is a member. */ - public void init(String username, Credentials credentials) { + public void init(String username, Credentials credentials, + Map tokens, Set effectiveGroups) { this.credentials = credentials; + this.effectiveGroups = effectiveGroups; + this.tokens = tokens; setIdentifier(username); } + + /** + * Get the tokens associated with this particular user. + * + * @return + * A map of token names and values available from this user account. + */ + public Map getTokens() { + return tokens; + } @Override public AuthenticationProvider getAuthenticationProvider() { @@ -67,5 +98,10 @@ public class SAMLAuthenticatedUser extends AbstractAuthenticatedUser { public Credentials getCredentials() { return credentials; } + + @Override + public Set getEffectiveUserGroups() { + return effectiveGroups; + } } From 52318a99a87f2b95bbcc652c867ff1836ddd016a Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Sat, 20 Jun 2020 09:57:40 -0400 Subject: [PATCH 08/12] GUACAMOLE-103: Handle group parsing in safe way --- .../saml/AuthenticationProviderService.java | 22 +++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index 718a0c0f7..74b98bcbb 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -21,7 +21,6 @@ package org.apache.guacamole.auth.saml; import com.google.inject.Inject; import com.google.inject.Provider; -import com.onelogin.saml2.Auth; import com.onelogin.saml2.authn.AuthnRequest; import com.onelogin.saml2.authn.SamlResponse; import com.onelogin.saml2.exception.SettingsException; @@ -29,12 +28,15 @@ import com.onelogin.saml2.exception.ValidationError; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; import java.io.IOException; +import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.Set; import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; @@ -113,9 +115,12 @@ public class AuthenticationProviderService { try { // Generate the response object - if (!samlResponseMap.hasSamlResponse(responseHash)) - throw new GuacamoleInvalidCredentialsException("Provided response has not found.", + if (!samlResponseMap.hasSamlResponse(responseHash)) { + logger.warn("SAML response was not found."); + logger.debug("SAML response hash {} not fonud in response map.", responseHash); + throw new GuacamoleInvalidCredentialsException("Provided response was not found.", CredentialsInfo.USERNAME_PASSWORD); + } SamlResponse samlResponse = samlResponseMap.getSamlResponse(responseHash); @@ -149,7 +154,7 @@ public class AuthenticationProviderService { authenticatedUser.init(username, credentials, parseTokens(attributes), - new HashSet<>(attributes.get(confService.getGroupAttribute()))); + parseGroups(attributes, confService.getGroupAttribute())); return authenticatedUser; } @@ -238,5 +243,14 @@ public class AuthenticationProviderService { return tokens; } + + private Set parseGroups(Map> attributes, String groupAttribute) throws GuacamoleException { + + List samlGroups = attributes.get(groupAttribute); + if (samlGroups != null && !samlGroups.isEmpty()) + return Collections.unmodifiableSet(new HashSet<>(samlGroups)); + + return Collections.emptySet(); + } } From 806ec964ff9570f3f9071d436fd88d44c722e27e Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Tue, 23 Jun 2020 13:53:10 -0400 Subject: [PATCH 09/12] GUACAMOLE-103: License cleanup, fix comments, and minor code tweaks. Includes implementation of executor shutdown, and correctly removing items from the shared response map. --- .../guacamole-auth-saml/src/licenses/LICENSE | 57 ++++- .../bundled/apache-commons-codec-1.12/LICENSE | 202 ++++++++++++++++++ .../bundled/apache-commons-lang-3.4/LICENSE | 202 ++++++++++++++++++ .../bundled/apache-santuario-2.1.4/LICENSE | 202 ++++++++++++++++++ .../LICENSE | 0 .../licenses/bundled/joda-time-2.10.3/LICENSE | 202 ++++++++++++++++++ .../bundled/woodstox-core-5.0.3/LICENSE | 202 ++++++++++++++++++ .../bundled/woodstox-stax2-api-3.1.4/LICENSE | 22 ++ .../saml/AuthenticationProviderService.java | 63 ++++-- .../auth/saml/SAMLAuthenticationProvider.java | 5 + .../SAMLAuthenticationProviderResource.java | 2 +- .../guacamole/auth/saml/SAMLResponseMap.java | 18 +- .../auth/saml/conf/ConfigurationService.java | 101 ++++----- .../auth/saml/form/SAMLRedirectField.java | 66 ------ .../auth/saml/user/SAMLAuthenticatedUser.java | 2 +- .../src/main/resources/translations/en.json | 4 +- 16 files changed, 1199 insertions(+), 151 deletions(-) create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-codec-1.12/LICENSE create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-lang-3.4/LICENSE create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/apache-santuario-2.1.4/LICENSE rename extensions/guacamole-auth-saml/src/licenses/bundled/{java-saml-2.2.0 => java-saml-2.5.0}/LICENSE (100%) create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/joda-time-2.10.3/LICENSE create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-core-5.0.3/LICENSE create mode 100644 extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-stax2-api-3.1.4/LICENSE delete mode 100644 extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java diff --git a/extensions/guacamole-auth-saml/src/licenses/LICENSE b/extensions/guacamole-auth-saml/src/licenses/LICENSE index 77bf5f6c4..fed687e8c 100644 --- a/extensions/guacamole-auth-saml/src/licenses/LICENSE +++ b/extensions/guacamole-auth-saml/src/licenses/LICENSE @@ -220,6 +220,33 @@ AOP Alliance (http://aopalliance.sourceforge.net/) Public Domain (bundled/aopalliance-1.0/LICENSE) +Apache Commons Codec (http://commons.apache.org/proper/commons-codec/) +----------------------------------------------------------------------- + + Version: 1.12 + From: 'Apache Software Foundation' (http://www.apache.org) + License(s): + Apache v2.0 (bundled/apache-commons-codec-1.12/LICENSE) + + +Apache Commons Lang (http://commons.apache.org/proper/commons-lang/) +--------------------------------------------------------------------- + + Version: 3.4 + From: 'Apache Software Foundation' (http://www.apache.org) + License(s): + Apache v2.0 (bundled/apache-commons-lang-3.4/LICENSE) + + +Apache Santuario (https://santuario.apache.org/) +------------------------------------------------- + + Version: 2.1.4 + From: 'Apache Software Foundation' (http://www.apache.org) + License(s): + Apache v2.0 (bundled/apache-santuario-2.1.4/LICENSE) + + Google Guice (https://github.com/google/guice) ---------------------------------------------- @@ -229,6 +256,15 @@ Google Guice (https://github.com/google/guice) Apache v2.0 (bundled/guice-3.0/COPYING) +Joda-Time (https://www.joda.org/joda-time/) +---------------------------------------------- + + Version: 2.10.3 + From: 'Joda.org' (https://www.joda.org/) + License(s): + Apache v2.0 (bundled/joda-time-2.10.3/COPYING) + + jose.4.j (https://bitbucket.org/b_c/jose4j/) -------------------------------------------- @@ -250,8 +286,25 @@ JSR-330 / Dependency Injection for Java (http://code.google.com/p/atinject/) Onelogin Java SAML Client (https://github.com/onelogin/java-saml) ------------------------------------------------------------------------ - Version: 2.2.0 + Version: 2.5.0 From: 'OneLogin' (https://www.onelogin.com) License(s): - MIT License (bundled/java-saml-2.2.0/LICENSE) + MIT License (bundled/java-saml-2.5.0/LICENSE) + +Woodstox Core (https://github.com/FasterXML/woodstox) +------------------------------------------------------ + + Version: 5.0.3 + From: 'FasterXML, LLC' (http://fasterxml.com/) + License(s): + Apache v2.0 (bundled/woodstox-core-5.0.3/LICENSE) + + +Woodstox Stax2-API (https://github.com/FasterXML/stax2-api) +------------------------------------------------------------ + + Version: 3.1.4 + From: 'FasterXML, LLC' (http://fasterxml.com/) + License(s): + BSD Simplified (bundled/woodstox-stax2-api-3.1.4/LICENSE) \ No newline at end of file diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-codec-1.12/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-codec-1.12/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-codec-1.12/LICENSE @@ -0,0 +1,202 @@ + + Apache 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. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-lang-3.4/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-lang-3.4/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/apache-commons-lang-3.4/LICENSE @@ -0,0 +1,202 @@ + + Apache 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. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/apache-santuario-2.1.4/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/apache-santuario-2.1.4/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/apache-santuario-2.1.4/LICENSE @@ -0,0 +1,202 @@ + + Apache 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. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.2.0/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.5.0/LICENSE similarity index 100% rename from extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.2.0/LICENSE rename to extensions/guacamole-auth-saml/src/licenses/bundled/java-saml-2.5.0/LICENSE diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/joda-time-2.10.3/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/joda-time-2.10.3/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/joda-time-2.10.3/LICENSE @@ -0,0 +1,202 @@ + + Apache 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. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-core-5.0.3/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-core-5.0.3/LICENSE new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-core-5.0.3/LICENSE @@ -0,0 +1,202 @@ + + Apache 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. diff --git a/extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-stax2-api-3.1.4/LICENSE b/extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-stax2-api-3.1.4/LICENSE new file mode 100644 index 000000000..19cbb6b58 --- /dev/null +++ b/extensions/guacamole-auth-saml/src/licenses/bundled/woodstox-stax2-api-3.1.4/LICENSE @@ -0,0 +1,22 @@ +Copyright 2008 FasterXML LLC + +Redistribution and use in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this +list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, +this list of conditions and the following disclaimer in the documentation +and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON +ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index 74b98bcbb..b7cde8244 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -28,7 +28,8 @@ import com.onelogin.saml2.exception.ValidationError; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.util.Util; import java.io.IOException; -import java.util.ArrayList; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; @@ -41,10 +42,11 @@ import javax.servlet.http.HttpServletRequest; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPathExpressionException; import org.apache.guacamole.auth.saml.conf.ConfigurationService; -import org.apache.guacamole.auth.saml.form.SAMLRedirectField; import org.apache.guacamole.auth.saml.user.SAMLAuthenticatedUser; import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.form.Field; +import org.apache.guacamole.form.RedirectField; +import org.apache.guacamole.language.TranslatableMessage; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.credentials.CredentialsInfo; @@ -130,12 +132,9 @@ public class AuthenticationProviderService { throw new GuacamoleInvalidCredentialsException("Error during SAML login.", CredentialsInfo.USERNAME_PASSWORD); } - if (!samlResponse.validateTimestamps()) { - logger.warn("SAML response timestamps were invalid."); - logger.debug("validateTimestamps returned false."); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); - } + + // Validate timestamps, generating ValidationException if this fails. + samlResponse.validateTimestamps(); // Grab the username, and, if present, finish authentication. String username = samlResponse.getNameId().toLowerCase(); @@ -208,10 +207,10 @@ public class AuthenticationProviderService { // No SAML Response is present, so generate a request. AuthnRequest samlReq = new AuthnRequest(samlSettings); - String reqString; + URI authUri; try { - reqString = samlSettings.getIdpSingleSignOnServiceUrl() + "?SAMLRequest=" + - Util.urlEncoder(samlReq.getEncodedAuthnRequest()); + authUri = new URI(samlSettings.getIdpSingleSignOnServiceUrl() + "?SAMLRequest=" + + Util.urlEncoder(samlReq.getEncodedAuthnRequest())); } catch (IOException e) { logger.error("Error encoding authentication request to string: {}", e.getMessage()); @@ -219,18 +218,37 @@ public class AuthenticationProviderService { throw new GuacamoleInvalidCredentialsException("Error during SAML login.", CredentialsInfo.USERNAME_PASSWORD); } + catch(URISyntaxException e) { + logger.error("Error generating URI for authentication redirect: {}", e.getMessage()); + logger.debug("Got URISyntaxException generating authentication URI", e); + throw new GuacamoleInvalidCredentialsException("Error during SAML login.", + CredentialsInfo.USERNAME_PASSWORD); + } // Redirect to SAML Identity Provider (IdP) throw new GuacamoleInsufficientCredentialsException("Redirecting to SAML IdP.", new CredentialsInfo(Arrays.asList(new Field[] { - new RedirectField("samlRedirect", reqString, "LOGIN.REDIRECT_PENDING") + new RedirectField("samlRedirect", authUri, new TranslatableMessage("LOGIN.INFO_SAML_REDIRECT_PENDING")) })) ); } - private Map parseTokens(Map> attributes) - throws GuacamoleException { + /** + * Generates Map of tokens that can be substituted within Guacamole + * parameters given a Map containing a List of attributes from the SAML IdP. + * Attributes that have multiple values will be reduced to a single value, + * taking the first available value and discarding the remaining values. + * + * @param attributes + * The Map containing the attributes retrieved from the SAML IdP. + * + * @return + * A Map of key and single value pairs that can be used as parameter + * tokens. + */ + private Map parseTokens(Map> attributes) { Map tokens = new HashMap<>(); for (Entry> entry : attributes.entrySet()) { @@ -244,7 +262,22 @@ public class AuthenticationProviderService { } - private Set parseGroups(Map> attributes, String groupAttribute) throws GuacamoleException { + /** + * Returns a list of groups found in the provided Map of attributes returned + * by the SAML IdP by searching the map for the provided group attribute. + * + * @param attributes + * The Map of attributes provided by the SAML IdP. + * + * @param groupAttribute + * The name of the attribute that may be present in the Map that + * will be used to parse group membership for the authenticated user. + * + * @return + * A Set of groups of which the user is a member. + */ + private Set parseGroups(Map> attributes, + String groupAttribute) { List samlGroups = attributes.get(groupAttribute); if (samlGroups != null && !samlGroups.isEmpty()) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java index a51d1050d..eb173d814 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProvider.java @@ -77,5 +77,10 @@ public class SAMLAuthenticationProvider extends AbstractAuthenticationProvider { return authProviderService.authenticateUser(credentials); } + + @Override + public void shutdown() { + injector.getInstance(SAMLResponseMap.class).shutdown(); + } } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java index 8ed52cd83..4a1e52199 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLAuthenticationProviderResource.java @@ -145,7 +145,7 @@ public class SAMLAuthenticationProviderResource { } /** - * This is a utility method designed to generate a SHA-256 has for the + * This is a utility method designed to generate a SHA-256 hash for the * given string representation of the SAMLResponse, throwing an exception * if, for some reason, the Java implementation in use doesn't support * SHA-256, and returning a hex-formatted hash value. diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java index 588811a99..392b8a13b 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java @@ -22,7 +22,7 @@ package org.apache.guacamole.auth.saml; import com.google.inject.Singleton; import com.onelogin.saml2.authn.SamlResponse; import com.onelogin.saml2.exception.ValidationError; -import java.util.Map.Entry; +import java.util.Collection; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executors; @@ -107,12 +107,13 @@ public class SAMLResponseMap { public void run() { // Loop through responses in map and remove ones that are no longer valid. - for (Entry entry : samlResponseMap.entrySet()) { + Collection samlResponses = samlResponseMap.values(); + for (SamlResponse value : samlResponses) { try { - entry.getValue().validateTimestamps(); + value.validateTimestamps(); } catch (ValidationError e) { - samlResponseMap.remove(entry.getKey()); + samlResponses.remove(value); } } @@ -120,4 +121,13 @@ public class SAMLResponseMap { } + /** + * Shut down the executor service that periodically cleans out the + * SamlResponse Map. This must be invoked during webapp shutdown in order + * to avoid resource leaks. + */ + public void shutdown() { + executor.shutdownNow(); + } + } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java index e216ccbca..f55d7b8ce 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java @@ -77,7 +77,8 @@ public class ConfigurationService { /** * The callback URL to use for SAML IdP, normally the base - * of the Guacamole install. + * of the Guacamole install. The SAML extensions callback + * endpoint will be appended to this value. */ private static final URIGuacamoleProperty SAML_CALLBACK_URL = new URIGuacamoleProperty() { @@ -86,17 +87,6 @@ public class ConfigurationService { public String getName() { return "saml-callback-url"; } }; - - /** - * The single logout redirect URL. - */ - private static final URIGuacamoleProperty SAML_LOGOUT_URL = - new URIGuacamoleProperty() { - - @Override - public String getName() { return "saml-logout-url"; } - - }; /** * Whether or not debugging should be enabled in the SAML library to help @@ -111,7 +101,7 @@ public class ConfigurationService { }; /** - * Whether or not to enabled compression for the SAML request. + * Whether or not to enable compression for the SAML request. */ private static final BooleanGuacamoleProperty SAML_COMPRESS_REQUEST = new BooleanGuacamoleProperty() { @@ -122,7 +112,7 @@ public class ConfigurationService { }; /** - * Whether or not to enabled compression for the SAML response. + * Whether or not to enable compression for the SAML response. */ private static final BooleanGuacamoleProperty SAML_COMPRESS_RESPONSE = new BooleanGuacamoleProperty() { @@ -162,13 +152,11 @@ public class ConfigurationService { private Environment environment; /** - * Returns the URL to be used as the client ID which will be - * submitted to the SAML IdP as configured in - * guacamole.properties. + * Returns the URL to be submitted as the client ID to the SAML IdP, as + * configured in guacamole.properties. * * @return - * The URL to be used as the client ID sent to the - * SAML IdP. + * The URL to send to the SAML IdP as the Client Identifier. * * @throws GuacamoleException * If guacamole.properties cannot be parsed, or if the @@ -180,7 +168,7 @@ public class ConfigurationService { /** * The file that contains the metadata that the SAML client should - * use to communicate with the SAML IdP. This is generated by the + * use to communicate with the SAML IdP. This is generated by the * SAML IdP and should be uploaded to the system where the Guacamole * client is running. * @@ -197,7 +185,7 @@ public class ConfigurationService { } /** - * Retrieve the URL used to log in to the SAML IdP. + * Return the URL used to log in to the SAML IdP. * * @return * The URL used to log in to the SAML IdP. @@ -225,23 +213,11 @@ public class ConfigurationService { public URI getCallbackUrl() throws GuacamoleException { return environment.getRequiredProperty(SAML_CALLBACK_URL); } - - /** - * Return the URL used to log out from the SAML IdP. - * - * @return - * The URL used to log out from the SAML IdP. - * - * @throws GuacamoleException - * If guacamole.properties cannot be parsed. - */ - private URI getLogoutUrl() throws GuacamoleException { - return environment.getProperty(SAML_LOGOUT_URL); - } /** - * Return true if SAML debugging should be enabled, otherwise false. The - * default is false. + * Return the Boolean value that indicates whether SAML client debugging + * will be enabled, as configured in guacamole.properties. The default is + * false, and debug information will not be generated or logged. * * @return * True if debugging should be enabled in the SAML library, otherwise @@ -250,13 +226,14 @@ public class ConfigurationService { * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ - private Boolean getDebug() throws GuacamoleException { + private boolean getDebug() throws GuacamoleException { return environment.getProperty(SAML_DEBUG, false); } /** - * Return true if compression should be enabled when sending the SAML - * request, otherwise false. The default is to enable compression. + * Return the Boolean value that indicates whether or not compression of + * SAML requests to the IdP should be enabled or not, as configured in + * guacamole.properties. The default is to enable compression. * * @return * True if compression should be enabled when sending the SAML request, @@ -265,14 +242,15 @@ public class ConfigurationService { * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ - private Boolean getCompressRequest() throws GuacamoleException { + private boolean getCompressRequest() throws GuacamoleException { return environment.getProperty(SAML_COMPRESS_REQUEST, true); } /** - * Returns whether or not the SAML login should enforce strict security - * controls. By default this is true, and should be set to true in any - * production environment. + * Return a Boolean value that indicates whether or not the SAML login + * should enforce strict security controls, as configured in + * guacamole.properties. By default this is true, and should be set to + * true in any production environment. * * @return * True if the SAML login should enforce strict security checks, @@ -281,14 +259,15 @@ public class ConfigurationService { * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ - private Boolean getStrict() throws GuacamoleException { + private boolean getStrict() throws GuacamoleException { return environment.getProperty(SAML_STRICT, true); } /** - * Return true if compression should be requested from the server when the - * SAML response is returned, otherwise false. The default is to request - * that the response be compressed. + * Return a Boolean value that indicates whether or not compression should + * be requested from the server when the SAML response is returned, as + * configured in guacamole.properties. The default is to request that the + * response be compressed. * * @return * True if compression should be requested from the server for the SAML @@ -297,7 +276,7 @@ public class ConfigurationService { * @throws GuacamoleException * If guacamole.properties cannot be parsed. */ - private Boolean getCompressResponse() throws GuacamoleException { + private boolean getCompressResponse() throws GuacamoleException { return environment.getProperty(SAML_COMPRESS_RESPONSE, true); } @@ -316,19 +295,18 @@ public class ConfigurationService { } /** - * Returns the collection of SAML settings used to - * initialize the client. + * Returns the collection of SAML settings used to initialize the client. * * @return - * The collection of SAML settings used to - * initialize the SAML client. + * The collection of SAML settings used to initialize the SAML client. * * @throws GuacamoleException - * If guacamole.properties cannot be parsed or - * if parameters are missing. + * If guacamole.properties cannot be parsed or if required parameters + * are missing. */ public Saml2Settings getSamlSettings() throws GuacamoleException { + // Try to get the XML file, first. File idpMetadata = getIdpMetadata(); Map samlMap; if (idpMetadata != null) { @@ -341,20 +319,23 @@ public class ConfigurationService { } } + // If no XML metadata is provided, fall-back to individual values. else { samlMap = new HashMap<>(); - samlMap.put(SettingsBuilder.SP_ENTITYID_PROPERTY_KEY, - getEntityId().toString()); - samlMap.put(SettingsBuilder.SP_ASSERTION_CONSUMER_SERVICE_URL_PROPERTY_KEY, - getCallbackUrl().toString() + "/api/ext/saml/callback"); - samlMap.put(SettingsBuilder.IDP_ENTITYID_PROPERTY_KEY - , getIdpUrl().toString()); + samlMap.put(SettingsBuilder.IDP_ENTITYID_PROPERTY_KEY, + getIdpUrl().toString()); samlMap.put(SettingsBuilder.IDP_SINGLE_SIGN_ON_SERVICE_URL_PROPERTY_KEY, getIdpUrl().toString()); samlMap.put(SettingsBuilder.IDP_SINGLE_SIGN_ON_SERVICE_BINDING_PROPERTY_KEY, Constants.BINDING_HTTP_REDIRECT); } + // Common settings, required with or without metadata file. + samlMap.put(SettingsBuilder.SP_ENTITYID_PROPERTY_KEY, + getEntityId().toString()); + samlMap.put(SettingsBuilder.SP_ASSERTION_CONSUMER_SERVICE_URL_PROPERTY_KEY, + getCallbackUrl().toString() + "/api/ext/saml/callback"); + SettingsBuilder samlBuilder = new SettingsBuilder(); Saml2Settings samlSettings = samlBuilder.fromValues(samlMap).build(); samlSettings.setStrict(getStrict()); diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java deleted file mode 100644 index f979b7805..000000000 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/form/SAMLRedirectField.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you 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. - */ - -package org.apache.guacamole.auth.saml.form; - -import org.apache.guacamole.form.Field; - -/** - * Field definition which represents the data used to do redirects - * during SAML authentication. - */ -public class SAMLRedirectField extends Field { - - /** - * The name of the parameter containing the redirect. - */ - public static final String PARAMETER_NAME = "samlRedirect"; - - /** - * The encoded URI of the redirect. - */ - private final String samlRedirect; - - /** - * Creates a new field which facilitates redirection of the user - * during SAML SSO authentication. - * - * @param samlRedirect - * The URI to which the user should be redirected. - */ - public SAMLRedirectField(String samlRedirect) { - - // Init base field properties - super(PARAMETER_NAME, "GUAC_SAML_REDIRECT"); - - this.samlRedirect = samlRedirect; - - } - - /** - * Returns the URI of the redirect. - * - * @return - * The URI of the redirect. - */ - public String getSamlRedirect() { - return samlRedirect; - } - -} diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java index 57c70a365..5228c99a1 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/user/SAMLAuthenticatedUser.java @@ -80,7 +80,7 @@ public class SAMLAuthenticatedUser extends AbstractAuthenticatedUser { } /** - * Get the tokens associated with this particular user. + * Returns a Map of tokens associated with this authenticated user. * * @return * A map of token names and values available from this user account. diff --git a/extensions/guacamole-auth-saml/src/main/resources/translations/en.json b/extensions/guacamole-auth-saml/src/main/resources/translations/en.json index 3ba3a85c5..b4f2d910f 100644 --- a/extensions/guacamole-auth-saml/src/main/resources/translations/en.json +++ b/extensions/guacamole-auth-saml/src/main/resources/translations/en.json @@ -1,12 +1,12 @@ { "DATA_SOURCE_SAML" : { - "NAME" : "SAML SSO Backend" + "NAME" : "SAML Authentication Extension" }, "LOGIN" : { "FIELD_HEADER_SAML" : "", - "INFO_SAML_REDIRECT_PENDING" : "Please wait, redirecting for SAML authentication..." + "INFO_SAML_REDIRECT_PENDING" : "Please wait, redirecting to identity provider..." } } From 27603dc2ac696626a77a7fc57683ff78abe1a593 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Wed, 24 Jun 2020 13:36:24 -0400 Subject: [PATCH 10/12] GUACAMOLE-103: Exception handling, token, and SAMLResponseMap updates. Exception handling within the SAML extension has been updated such that exceptions generate a Guacamole Error rather than a username/password login. Tokens now are canonicalized with a standard prefix. Now using an Iterator to handle SAMLResponseMap cleanup. --- .../saml/AuthenticationProviderService.java | 48 ++++++++----------- .../guacamole/auth/saml/SAMLResponseMap.java | 9 ++-- 2 files changed, 26 insertions(+), 31 deletions(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index b7cde8244..b256e9b70 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -44,14 +44,15 @@ import javax.xml.xpath.XPathExpressionException; import org.apache.guacamole.auth.saml.conf.ConfigurationService; import org.apache.guacamole.auth.saml.user.SAMLAuthenticatedUser; import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.form.Field; import org.apache.guacamole.form.RedirectField; import org.apache.guacamole.language.TranslatableMessage; import org.apache.guacamole.net.auth.AuthenticatedUser; import org.apache.guacamole.net.auth.Credentials; import org.apache.guacamole.net.auth.credentials.CredentialsInfo; -import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException; import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; +import org.apache.guacamole.token.TokenName; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.xml.sax.SAXException; @@ -64,7 +65,7 @@ public class AuthenticationProviderService { /** * Logger for this class. */ - private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class); + private static final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class); /** * Service for retrieving SAML configuration information. @@ -83,6 +84,8 @@ public class AuthenticationProviderService { */ @Inject private SAMLResponseMap samlResponseMap; + + private static final String SAML_ATTRIBUTE_TOKEN_PREFIX = "SAML_"; /** * Returns an AuthenticatedUser representing the user authenticated by the @@ -119,9 +122,8 @@ public class AuthenticationProviderService { // Generate the response object if (!samlResponseMap.hasSamlResponse(responseHash)) { logger.warn("SAML response was not found."); - logger.debug("SAML response hash {} not fonud in response map.", responseHash); - throw new GuacamoleInvalidCredentialsException("Provided response was not found.", - CredentialsInfo.USERNAME_PASSWORD); + logger.debug("SAML response hash {} not found in response map.", responseHash); + throw new GuacamoleServerException("Provided response was not found in response map."); } SamlResponse samlResponse = samlResponseMap.getSamlResponse(responseHash); @@ -129,8 +131,7 @@ public class AuthenticationProviderService { if (!samlResponse.validateNumAssertions()) { logger.warn("SAML response contained other than single assertion."); logger.debug("validateNumAssertions returned false."); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("Unable to validate SAML assertions."); } // Validate timestamps, generating ValidationException if this fails. @@ -159,48 +160,41 @@ public class AuthenticationProviderService { } } - // Errors are logged and result in a normal username/password login box. + // Catch errors and convert to a GuacamoleExcetion. catch (IOException e) { logger.warn("Error during I/O while parsing SAML response: {}", e.getMessage()); logger.debug("Received IOException when trying to parse SAML response.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("IOException received while processing SAML response.", e); } catch (ParserConfigurationException e) { logger.warn("Error configuring XML parser: {}", e.getMessage()); logger.debug("Received ParserConfigurationException when trying to parse SAML response.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("XML ParserConfigurationException received while processing SAML response.", e); } catch (SAXException e) { logger.warn("Bad XML when parsing SAML response: {}", e.getMessage()); logger.debug("Received SAXException while parsing SAML response.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("XML SAXException received while processing SAML response.", e); } catch (SettingsException e) { logger.warn("Error with SAML settings while parsing response: {}", e.getMessage()); logger.debug("Received SettingsException while parsing SAML response.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("SAML SettingsException received while process SAML response.", e); } catch (ValidationError e) { logger.warn("Error validating SAML response: {}", e.getMessage()); logger.debug("Received ValidationError while parsing SAML response.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("SAML ValidationError received while processing SAML response.", e); } catch (XPathExpressionException e) { logger.warn("Problem with XML parsing response: {}", e.getMessage()); logger.debug("Received XPathExpressionException while processing SAML response.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("XML XPathExpressionExcetion received while processing SAML response.", e); } catch (Exception e) { logger.warn("Exception while getting name from SAML response: {}", e.getMessage()); logger.debug("Received Exception while retrieving name from SAML response.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("Generic Exception received processing SAML response.", e); } } } @@ -215,14 +209,12 @@ public class AuthenticationProviderService { catch (IOException e) { logger.error("Error encoding authentication request to string: {}", e.getMessage()); logger.debug("Got IOException encoding authentication request.", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("IOException received while generating SAML authentication URI.", e); } catch(URISyntaxException e) { logger.error("Error generating URI for authentication redirect: {}", e.getMessage()); logger.debug("Got URISyntaxException generating authentication URI", e); - throw new GuacamoleInvalidCredentialsException("Error during SAML login.", - CredentialsInfo.USERNAME_PASSWORD); + throw new GuacamoleServerException("URISyntaxException received while generating SAML authentication URI.", e); } // Redirect to SAML Identity Provider (IdP) @@ -254,7 +246,9 @@ public class AuthenticationProviderService { for (Entry> entry : attributes.entrySet()) { List values = entry.getValue(); - tokens.put(entry.getKey(), values.get(0)); + tokens.put(TokenName.canonicalize( + entry.getKey(), SAML_ATTRIBUTE_TOKEN_PREFIX), + values.get(0)); } diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java index 392b8a13b..90109961a 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/SAMLResponseMap.java @@ -23,6 +23,7 @@ import com.google.inject.Singleton; import com.onelogin.saml2.authn.SamlResponse; import com.onelogin.saml2.exception.ValidationError; import java.util.Collection; +import java.util.Iterator; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.Executors; @@ -107,13 +108,13 @@ public class SAMLResponseMap { public void run() { // Loop through responses in map and remove ones that are no longer valid. - Collection samlResponses = samlResponseMap.values(); - for (SamlResponse value : samlResponses) { + Iterator responseIterator = samlResponseMap.values().iterator(); + while (responseIterator.hasNext()) { try { - value.validateTimestamps(); + responseIterator.next().validateTimestamps(); } catch (ValidationError e) { - samlResponses.remove(value); + responseIterator.remove(); } } From 1f0174afeacf2ee6f6c126d792675d6abb8aa0a3 Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Wed, 24 Jun 2020 15:19:10 -0400 Subject: [PATCH 11/12] GUACAMOLE-103: Redirect for login if response hash is not present. --- .../auth/saml/AuthenticationProviderService.java | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java index b256e9b70..ddc6dbde5 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/AuthenticationProviderService.java @@ -115,16 +115,9 @@ public class AuthenticationProviderService { // Look for the SAML Response parameter. String responseHash = request.getParameter("responseHash"); - if (responseHash != null) { + if (responseHash != null && samlResponseMap.hasSamlResponse(responseHash)) { try { - - // Generate the response object - if (!samlResponseMap.hasSamlResponse(responseHash)) { - logger.warn("SAML response was not found."); - logger.debug("SAML response hash {} not found in response map.", responseHash); - throw new GuacamoleServerException("Provided response was not found in response map."); - } SamlResponse samlResponse = samlResponseMap.getSamlResponse(responseHash); @@ -199,7 +192,7 @@ public class AuthenticationProviderService { } } - // No SAML Response is present, so generate a request. + // No SAML Response is present, or hash is not present in map. AuthnRequest samlReq = new AuthnRequest(samlSettings); URI authUri; try { From 8acb3cbb24845360d8b2106bbe4cc573b454860d Mon Sep 17 00:00:00 2001 From: Virtually Nick Date: Wed, 24 Jun 2020 15:56:17 -0400 Subject: [PATCH 12/12] GUACAMOLE-103: Change IdP metadata file to a URI. --- .../auth/saml/conf/ConfigurationService.java | 29 ++++++++++--------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java index f55d7b8ce..ca830cfd1 100644 --- a/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java +++ b/extensions/guacamole-auth-saml/src/main/java/org/apache/guacamole/auth/saml/conf/ConfigurationService.java @@ -24,7 +24,6 @@ import com.onelogin.saml2.settings.IdPMetadataParser; import com.onelogin.saml2.settings.Saml2Settings; import com.onelogin.saml2.settings.SettingsBuilder; import com.onelogin.saml2.util.Constants; -import java.io.File; import java.net.URI; import java.util.HashMap; import java.util.Map; @@ -32,7 +31,6 @@ import org.apache.guacamole.GuacamoleException; import org.apache.guacamole.GuacamoleServerException; import org.apache.guacamole.environment.Environment; import org.apache.guacamole.properties.BooleanGuacamoleProperty; -import org.apache.guacamole.properties.FileGuacamoleProperty; import org.apache.guacamole.properties.StringGuacamoleProperty; import org.apache.guacamole.properties.URIGuacamoleProperty; @@ -43,13 +41,14 @@ import org.apache.guacamole.properties.URIGuacamoleProperty; public class ConfigurationService { /** - * The file containing the XML Metadata associated with the SAML IdP. + * The URI of the file containing the XML Metadata associated with the + * SAML IdP. */ - private static final FileGuacamoleProperty SAML_IDP_METADATA = - new FileGuacamoleProperty() { + private static final URIGuacamoleProperty SAML_IDP_METADATA = + new URIGuacamoleProperty() { @Override - public String getName() { return "saml-idp-metadata"; } + public String getName() { return "saml-idp-metadata-url"; } }; @@ -167,20 +166,22 @@ public class ConfigurationService { } /** - * The file that contains the metadata that the SAML client should - * use to communicate with the SAML IdP. This is generated by the - * SAML IdP and should be uploaded to the system where the Guacamole - * client is running. + * The URI that contains the metadata that the SAML client should + * use to communicate with the SAML IdP. This can either be a remote + * URL of a server that provides this, or can be a URI to a file on the + * local filesystem. The metadata file is usually generated by the SAML IdP + * and should be uploaded to the system where the Guacamole client is + * running. * * @return - * The file containing the metadata used by the SAML client + * The URI of the file containing the metadata used by the SAML client * when it communicates with the SAML IdP. * * @throws GuacamoleException * If guacamole.properties cannot be parsed, or if the client * metadata is missing. */ - private File getIdpMetadata() throws GuacamoleException { + private URI getIdpMetadata() throws GuacamoleException { return environment.getProperty(SAML_IDP_METADATA); } @@ -307,11 +308,11 @@ public class ConfigurationService { public Saml2Settings getSamlSettings() throws GuacamoleException { // Try to get the XML file, first. - File idpMetadata = getIdpMetadata(); + URI idpMetadata = getIdpMetadata(); Map samlMap; if (idpMetadata != null) { try { - samlMap = IdPMetadataParser.parseFileXML(idpMetadata.getAbsolutePath()); + samlMap = IdPMetadataParser.parseRemoteXML(idpMetadata.toURL()); } catch (Exception e) { throw new GuacamoleServerException(