diff --git a/LICENSE b/LICENSE index 2c1ab31b3..3fa304c53 100644 --- a/LICENSE +++ b/LICENSE @@ -254,3 +254,40 @@ 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. + +TOTP Reference Implementation (https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl) +------------------------------------------------------------------------------- + + Verson: 07 + From: 'IETF Trust' (http://trustee.ietf.org/license-info) + License(s): + BSD 3-clause (extensions/guacamole-auth-duo/src/licenses/bundled/totp-reference-impl-07/license.txt) + +Copyright (c) 2011 IETF Trust and the persons identified as authors +of the code. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + - 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. + + - Neither the name of Internet Society, IETF or IETF Trust, nor the names + of specific contributors, may be used to endorse or promote products + derived from this software without specific prior written permission. + +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 OWNER 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. + diff --git a/extensions/guacamole-auth-totp/.gitignore b/extensions/guacamole-auth-totp/.gitignore new file mode 100644 index 000000000..1de9633ae --- /dev/null +++ b/extensions/guacamole-auth-totp/.gitignore @@ -0,0 +1,3 @@ +src/main/resources/generated/ +target/ +*~ diff --git a/extensions/guacamole-auth-totp/pom.xml b/extensions/guacamole-auth-totp/pom.xml new file mode 100644 index 000000000..af4445581 --- /dev/null +++ b/extensions/guacamole-auth-totp/pom.xml @@ -0,0 +1,274 @@ + + + + + 4.0.0 + org.apache.guacamole + guacamole-auth-totp + jar + 0.9.14 + guacamole-auth-totp + http://guacamole.incubator.apache.org/ + + + UTF-8 + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.3 + + 1.6 + 1.6 + + -Xlint:all + -Werror + + true + + + + + + com.keithbranton.mojo + angular-maven-plugin + 0.3.2 + + + generate-resources + + html2js + + + + + ${basedir}/src/main/resources + **/*.html + ${basedir}/src/main/resources/generated/templates-main/templates.js + app/ext/totp + + + + + + com.samaxes.maven + minify-maven-plugin + 1.7.5 + + + default-cli + + UTF-8 + + ${basedir}/src/main/resources + ${project.build.directory}/classes + + / + / + totp.css + + + license.txt + + + + **/*.css + + + / + / + totp.js + + + license.txt + + + + **/*.js + + + + + **/*.test.js + + CLOSURE + + + + OFF + OFF + + + + + minify + + + + + + + + maven-assembly-plugin + 2.5.3 + + ${project.artifactId}-${project.version} + false + + src/main/assembly/dist.xml + + + + + make-dist-archive + package + + single + + + + + + + + org.apache.maven.plugins + maven-dependency-plugin + 2.10 + + + unpack-dependencies + prepare-package + + unpack-dependencies + + + runtime + ${project.build.directory}/classes + + + + + + + + org.apache.rat + apache-rat-plugin + 0.12 + + + + **/*.json + src/licenses/**/* + src/main/resources/templates/*.html + + + + + + + validate + validate + + check + + + + + + + + + + + + + + org.apache.guacamole + guacamole-ext + 0.9.14 + provided + + + + + com.google.inject + guice + 3.0 + + + com.google.inject.extensions + guice-multibindings + 3.0 + + + + + javax.servlet + servlet-api + 2.5 + provided + + + + + com.google.guava + guava + 18.0 + + + + + junit + junit + 4.12 + test + + + + + com.google.zxing + javase + 3.3.1 + + + com.google.zxing + core + 3.3.1 + + + + + javax.ws.rs + javax.ws.rs-api + 2.0 + provided + + + + + diff --git a/extensions/guacamole-auth-totp/src/licenses/LICENSE b/extensions/guacamole-auth-totp/src/licenses/LICENSE new file mode 100644 index 000000000..8a66d231a --- /dev/null +++ b/extensions/guacamole-auth-totp/src/licenses/LICENSE @@ -0,0 +1,294 @@ + + 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) + + +Guava: Google Core Libraries for Java (https://github.com/google/guava) +----------------------------------------------------------------------- + + Version: 18.0 + From: 'Google Inc.' (http://www.google.com/) + License(s): + Apache v2.0 (bundled/guava-18.0/COPYING) + + +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) + + +TOTP Reference Implementation (https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl) +------------------------------------------------------------------------------- + + Verson: 07 + From: 'IETF Trust' (http://trustee.ietf.org/license-info) + License(s): + BSD 3-clause (bundled/totp-reference-impl-07/license.txt) + +Copyright (c) 2011 IETF Trust and the persons identified as authors +of the code. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + - 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. + + - Neither the name of Internet Society, IETF or IETF Trust, nor the names + of specific contributors, may be used to endorse or promote products + derived from this software without specific prior written permission. + +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 OWNER 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. + + +ZXing Barcode Scanning Library (https://github.com/zxing/zxing/) +---------------------------------------------------------------- + + Version: 3.3.1 + From: 'ZXing authors' (https://github.com/zxing/zxing/blob/zxing-3.3.1/AUTHORS) + License(s): + Apache v2.0 (bundled/zxing-3.3.1/LICENSE) + diff --git a/extensions/guacamole-auth-totp/src/licenses/NOTICE b/extensions/guacamole-auth-totp/src/licenses/NOTICE new file mode 100644 index 000000000..47f2b4c24 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/licenses/NOTICE @@ -0,0 +1,5 @@ +Apache Guacamole +Copyright 2017 The Apache Software Foundation + +This product includes software developed at +The Apache Software Foundation (http://www.apache.org/). diff --git a/extensions/guacamole-auth-totp/src/licenses/bundled/README b/extensions/guacamole-auth-totp/src/licenses/bundled/README new file mode 100644 index 000000000..47ba19db0 --- /dev/null +++ b/extensions/guacamole-auth-totp/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-totp/src/licenses/bundled/aopalliance-1.0/LICENSE b/extensions/guacamole-auth-totp/src/licenses/bundled/aopalliance-1.0/LICENSE new file mode 100644 index 000000000..8e0e3786b --- /dev/null +++ b/extensions/guacamole-auth-totp/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-totp/src/licenses/bundled/guava-18.0/COPYING b/extensions/guacamole-auth-totp/src/licenses/bundled/guava-18.0/COPYING new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/licenses/bundled/guava-18.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-totp/src/licenses/bundled/guice-3.0/COPYING b/extensions/guacamole-auth-totp/src/licenses/bundled/guice-3.0/COPYING new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-totp/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-totp/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt b/extensions/guacamole-auth-totp/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt new file mode 100644 index 000000000..d64569567 --- /dev/null +++ b/extensions/guacamole-auth-totp/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-totp/src/licenses/bundled/totp-reference-impl-07/license.txt b/extensions/guacamole-auth-totp/src/licenses/bundled/totp-reference-impl-07/license.txt new file mode 100644 index 000000000..bb1afcd2c --- /dev/null +++ b/extensions/guacamole-auth-totp/src/licenses/bundled/totp-reference-impl-07/license.txt @@ -0,0 +1,28 @@ +Copyright (c) 2011 IETF Trust and the persons identified as authors +of the code. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + - Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + - 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. + + - Neither the name of Internet Society, IETF or IETF Trust, nor the names + of specific contributors, may be used to endorse or promote products + derived from this software without specific prior written permission. + +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 OWNER 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. + diff --git a/extensions/guacamole-auth-totp/src/licenses/bundled/zxing-3.3.1/LICENSE b/extensions/guacamole-auth-totp/src/licenses/bundled/zxing-3.3.1/LICENSE new file mode 100644 index 000000000..510991eda --- /dev/null +++ b/extensions/guacamole-auth-totp/src/licenses/bundled/zxing-3.3.1/LICENSE @@ -0,0 +1,245 @@ + 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. + +======================================================================== +jai-imageio +======================================================================== + +Copyright (c) 2005 Sun Microsystems, Inc. +Copyright © 2010-2014 University of Manchester +Copyright © 2010-2015 Stian Soiland-Reyes +Copyright © 2015 Peter Hull +All Rights Reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +- Redistribution of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +- Redistribution 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. + +Neither the name of Sun Microsystems, Inc. or the names of +contributors may be used to endorse or promote products derived +from this software without specific prior written permission. + +This software is provided "AS IS," without a warranty of any +kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND +WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY +EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL +NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF +USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS +DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR +ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, +CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND +REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR +INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + +You acknowledge that this software is not designed or intended for +use in the design, construction, operation or maintenance of any +nuclear facility. \ No newline at end of file diff --git a/extensions/guacamole-auth-totp/src/main/assembly/dist.xml b/extensions/guacamole-auth-totp/src/main/assembly/dist.xml new file mode 100644 index 000000000..b89fd534c --- /dev/null +++ b/extensions/guacamole-auth-totp/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-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProvider.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProvider.java new file mode 100644 index 000000000..4f18304a7 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProvider.java @@ -0,0 +1,126 @@ +/* + * 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.totp; + +import org.apache.guacamole.auth.totp.user.UserVerificationService; +import com.google.inject.Guice; +import com.google.inject.Injector; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.totp.user.CodeUsageTrackingService; +import org.apache.guacamole.auth.totp.user.TOTPUserContext; +import org.apache.guacamole.net.auth.AuthenticatedUser; +import org.apache.guacamole.net.auth.AuthenticationProvider; +import org.apache.guacamole.net.auth.Credentials; +import org.apache.guacamole.net.auth.UserContext; + +/** + * AuthenticationProvider implementation which uses TOTP as an additional + * authentication factor for users which have already been authenticated by + * some other AuthenticationProvider. + */ +public class TOTPAuthenticationProvider implements AuthenticationProvider { + + /** + * Injector which will manage the object graph of this authentication + * provider. + */ + private final Injector injector; + + /** + * Creates a new TOTPAuthenticationProvider that verifies users using TOTP. + * + * @throws GuacamoleException + * If a required property is missing, or an error occurs while parsing + * a property. + */ + public TOTPAuthenticationProvider() throws GuacamoleException { + + // Set up Guice injector. + injector = Guice.createInjector( + new TOTPAuthenticationProviderModule(this) + ); + + } + + @Override + public String getIdentifier() { + return "totp"; + } + + @Override + public Object getResource() { + return null; + } + + @Override + public AuthenticatedUser authenticateUser(Credentials credentials) + throws GuacamoleException { + return null; + } + + @Override + public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser, + Credentials credentials) throws GuacamoleException { + return authenticatedUser; + } + + @Override + public UserContext getUserContext(AuthenticatedUser authenticatedUser) + throws GuacamoleException { + return null; + } + + @Override + public UserContext updateUserContext(UserContext context, + AuthenticatedUser authenticatedUser, Credentials credentials) + throws GuacamoleException { + return context; + } + + @Override + public UserContext decorate(UserContext context, + AuthenticatedUser authenticatedUser, Credentials credentials) + throws GuacamoleException { + + UserVerificationService verificationService = + injector.getInstance(UserVerificationService.class); + + // Verify identity of user + verificationService.verifyIdentity(context, authenticatedUser); + + // User has been verified, and authentication should be allowed to + // continue + return new TOTPUserContext(context); + + } + + @Override + public UserContext redecorate(UserContext decorated, UserContext context, + AuthenticatedUser authenticatedUser, Credentials credentials) + throws GuacamoleException { + return new TOTPUserContext(context); + } + + @Override + public void shutdown() { + injector.getInstance(CodeUsageTrackingService.class).shutdown(); + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProviderModule.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProviderModule.java new file mode 100644 index 000000000..d1f7f9616 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/TOTPAuthenticationProviderModule.java @@ -0,0 +1,83 @@ +/* + * 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.totp; + +import org.apache.guacamole.auth.totp.user.UserVerificationService; +import com.google.inject.AbstractModule; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.totp.conf.ConfigurationService; +import org.apache.guacamole.auth.totp.user.CodeUsageTrackingService; +import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.environment.LocalEnvironment; +import org.apache.guacamole.net.auth.AuthenticationProvider; + +/** + * Guice module which configures TOTP-specific injections. + */ +public class TOTPAuthenticationProviderModule extends AbstractModule { + + /** + * Guacamole server environment. + */ + private final Environment environment; + + /** + * A reference to the TOTPAuthenticationProvider on behalf of which this + * module has configured injection. + */ + private final AuthenticationProvider authProvider; + + /** + * Creates a new TOTP authentication provider module which configures + * injection for the TOTPAuthenticationProvider. + * + * @param authProvider + * The AuthenticationProvider for which injection is being configured. + * + * @throws GuacamoleException + * If an error occurs while retrieving the Guacamole server + * environment. + */ + public TOTPAuthenticationProviderModule(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 TOTP-specific services + bind(CodeUsageTrackingService.class); + bind(ConfigurationService.class); + bind(UserVerificationService.class); + + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/ConfigurationService.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/ConfigurationService.java new file mode 100644 index 000000000..8658849be --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/ConfigurationService.java @@ -0,0 +1,161 @@ +/* + * 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.totp.conf; + +import com.google.inject.Inject; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleServerException; +import org.apache.guacamole.environment.Environment; +import org.apache.guacamole.properties.IntegerGuacamoleProperty; +import org.apache.guacamole.properties.StringGuacamoleProperty; +import org.apache.guacamole.totp.TOTPGenerator; + +/** + * Service for retrieving configuration information regarding the TOTP + * authentication extension. + */ +public class ConfigurationService { + + /** + * The Guacamole server environment. + */ + @Inject + private Environment environment; + + /** + * The human-readable name of the entity issuing user accounts. By default, + * this will be "Apache Guacamole". + */ + private static final StringGuacamoleProperty TOTP_ISSUER = + new StringGuacamoleProperty() { + + @Override + public String getName() { return "totp-issuer"; } + + }; + + /** + * The number of digits which should be included in each generated TOTP + * code. By default, this will be 6. + */ + private static final IntegerGuacamoleProperty TOTP_DIGITS= + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "totp-digits"; } + + }; + + /** + * The duration that each generated code should remain valid, in seconds. + * By default, this will be 30. + */ + private static final IntegerGuacamoleProperty TOTP_PERIOD = + new IntegerGuacamoleProperty() { + + @Override + public String getName() { return "totp-period"; } + + }; + + /** + * The hash algorithm that should be used to generate TOTP codes. By + * default, this will be "sha1". Legal values are "sha1", "sha256", and + * "sha512". + */ + private static final TOTPModeProperty TOTP_MODE = + new TOTPModeProperty() { + + @Override + public String getName() { return "totp-mode"; } + + }; + + /** + * Returns the human-readable name of the entity issuing user accounts. If + * not specified, "Apache Guacamole" will be used by default. + * + * @return + * The human-readable name of the entity issuing user accounts. + * + * @throws GuacamoleException + * If the "totp-issuer" property cannot be read from + * guacamole.properties. + */ + public String getIssuer() throws GuacamoleException { + return environment.getProperty(TOTP_ISSUER, "Apache Guacamole"); + } + + /** + * Returns the number of digits which should be included in each generated + * TOTP code. If not specified, 6 will be used by default. + * + * @return + * The number of digits which should be included in each generated + * TOTP code. + * + * @throws GuacamoleException + * If the "totp-digits" property cannot be read from + * guacamole.properties. + */ + public int getDigits() throws GuacamoleException { + + // Validate legal number of digits + int digits = environment.getProperty(TOTP_DIGITS, 6); + if (digits < 6 || digits > 8) + throw new GuacamoleServerException("TOTP codes may have no fewer " + + "than 6 digits and no more than 8 digits."); + + return digits; + + } + + /** + * Returns the duration that each generated code should remain valid, in + * seconds. If not specified, 30 will be used by default. + * + * @return + * The duration that each generated code should remain valid, in + * seconds. + * + * @throws GuacamoleException + * If the "totp-period" property cannot be read from + * guacamole.properties. + */ + public int getPeriod() throws GuacamoleException { + return environment.getProperty(TOTP_PERIOD, 30); + } + + /** + * Returns the hash algorithm that should be used to generate TOTP codes. If + * not specified, SHA1 will be used by default. + * + * @return + * The hash algorithm that should be used to generate TOTP codes. + * + * @throws GuacamoleException + * If the "totp-mode" property cannot be read from + * guacamole.properties. + */ + public TOTPGenerator.Mode getMode() throws GuacamoleException { + return environment.getProperty(TOTP_MODE, TOTPGenerator.Mode.SHA1); + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/TOTPModeProperty.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/TOTPModeProperty.java new file mode 100644 index 000000000..bfe3ef307 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/conf/TOTPModeProperty.java @@ -0,0 +1,62 @@ +/* + * 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.totp.conf; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleServerException; +import org.apache.guacamole.properties.GuacamoleProperty; +import org.apache.guacamole.totp.TOTPGenerator; + +/** + * A GuacamoleProperty whose value is a TOTP generation method. The string + * values "sha1", "sha256", and "sha512" are each parsed to their corresponding + * values within the TOTPGenerator.Mode enum. All other string values result in + * parse errors. + */ +public abstract class TOTPModeProperty + implements GuacamoleProperty { + + @Override + public TOTPGenerator.Mode parseValue(String value) + throws GuacamoleException { + + // If no value provided, return null. + if (value == null) + return null; + + // SHA1 + if (value.equals("sha1")) + return TOTPGenerator.Mode.SHA1; + + // SHA256 + if (value.equals("sha256")) + return TOTPGenerator.Mode.SHA256; + + // SHA512 + if (value.equals("sha512")) + return TOTPGenerator.Mode.SHA512; + + // The provided value is not legal + throw new GuacamoleServerException("TOTP mode must be one of " + + "\"sha1\", \"sha256\", or \"sha512\"."); + + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/form/AuthenticationCodeField.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/form/AuthenticationCodeField.java new file mode 100644 index 000000000..1a61e8982 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/form/AuthenticationCodeField.java @@ -0,0 +1,316 @@ +/* + * 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.totp.form; + +import com.google.common.io.BaseEncoding; +import com.google.inject.Inject; +import com.google.zxing.BarcodeFormat; +import com.google.zxing.WriterException; +import com.google.zxing.client.j2se.MatrixToImageWriter; +import com.google.zxing.common.BitMatrix; +import com.google.zxing.qrcode.QRCodeWriter; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.net.URI; +import javax.ws.rs.core.UriBuilder; +import javax.xml.bind.DatatypeConverter; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.totp.user.UserTOTPKey; +import org.apache.guacamole.auth.totp.conf.ConfigurationService; +import org.apache.guacamole.form.Field; +import org.apache.guacamole.totp.TOTPGenerator; +import org.codehaus.jackson.annotate.JsonProperty; + +/** + * Field which prompts the user for an authentication code generated via TOTP. + */ +public class AuthenticationCodeField extends Field { + + /** + * The name of the HTTP parameter which will contain the TOTP code provided + * by the user to verify their identity. + */ + public static final String PARAMETER_NAME = "guac-totp"; + + /** + * The unique name associated with this field type. + */ + private static final String FIELD_TYPE_NAME = "GUAC_TOTP_CODE"; + + /** + * The width of QR codes to generate, in pixels. + */ + private static final int QR_CODE_WIDTH = 256; + + /** + * The height of QR codes to generate, in pixels. + */ + private static final int QR_CODE_HEIGHT = 256; + + /** + * BaseEncoding which encodes/decodes base32. + */ + private static final BaseEncoding BASE32 = BaseEncoding.base32(); + + /** + * Service for retrieving configuration information. + */ + @Inject + private ConfigurationService confService; + + /** + * The TOTP key to expose to the user for the sake of enrollment, if any. + * If no such key should be exposed to the user, this will be null. + */ + private UserTOTPKey key; + + /** + * Creates a new field which prompts the user for an authentication code + * generated via TOTP. The user's TOTP key is not exposed for enrollment. + */ + public AuthenticationCodeField() { + super(PARAMETER_NAME, FIELD_TYPE_NAME); + } + + /** + * Exposes the given key to facilitate enrollment. + * + * @param key + * The TOTP key to expose to the user for the sake of enrollment. + */ + public void exposeKey(UserTOTPKey key) { + this.key = key; + } + + /** + * Returns the username of the user associated with the key being used to + * generate TOTP codes. If the user's key is not being exposed to facilitate + * enrollment, this value will not be exposed either. + * + * @return + * The username of the user associated with the key being used to + * generate TOTP codes, or null if the user's key is not being exposed + * to facilitate enrollment. + */ + public String getUsername() { + + // Do not reveal TOTP mode unless enrollment is in progress + if (key == null) + return null; + + return key.getUsername(); + + } + + /** + * Returns the base32-encoded secret key that is being used to generate TOTP + * codes for the authenticating user. If the user's key is not being exposed + * to facilitate enrollment, this value will not be exposed either. + * + * @return + * The base32-encoded secret key that is being used to generate TOTP + * codes for the authenticating user, or null if the user's key is not + * being exposed to facilitate enrollment. + */ + public String getSecret() { + + // Do not reveal TOTP mode unless enrollment is in progress + if (key == null) + return null; + + return BASE32.encode(key.getSecret()); + + } + + /** + * Returns the number of digits used for each TOTP code. If the user's key + * is not being exposed to facilitate enrollment, this value will not be + * exposed either. + * + * @return + * The number of digits used for each TOTP code, or null if the user's + * key is not being exposed to facilitate enrollment. + * + * @throws GuacamoleException + * If the number of digits cannot be read from guacamole.properties. + */ + public Integer getDigits() throws GuacamoleException { + + // Do not reveal code size unless enrollment is in progress + if (key == null) + return null; + + return confService.getDigits(); + + } + + /** + * Returns the human-readable name of the entity issuing user accounts. If + * the user's key is not being exposed to facilitate enrollment, this value + * will not be exposed either. + * + * @return + * The human-readable name of the entity issuing user accounts, or null + * if the user's key is not being exposed to facilitate enrollment. + * + * @throws GuacamoleException + * If the issuer cannot be read from guacamole.properties. + */ + public String getIssuer() throws GuacamoleException { + + // Do not reveal code issuer unless enrollment is in progress + if (key == null) + return null; + + return confService.getIssuer(); + + } + + /** + * Returns the mode that TOTP code generation is operating in. This value + * will be one of "SHA1", "SHA256", or "SHA512". If the user's key is not + * being exposed to facilitate enrollment, this value will not be exposed + * either. + * + * @return + * The mode that TOTP code generation is operating in, such as "SHA1", + * "SHA256", or "SHA512", or null if the user's key is not being + * exposed to facilitate enrollment. + * + * @throws GuacamoleException + * If the TOTP mode cannot be read from guacamole.properties. + */ + public TOTPGenerator.Mode getMode() throws GuacamoleException { + + // Do not reveal TOTP mode unless enrollment is in progress + if (key == null) + return null; + + return confService.getMode(); + + } + + /** + * Returns the number of seconds that each TOTP code remains valid. If the + * user's key is not being exposed to facilitate enrollment, this value will + * not be exposed either. + * + * @return + * The number of seconds that each TOTP code remains valid, or null if + * the user's key is not being exposed to facilitate enrollment. + * + * @throws GuacamoleException + * If the period cannot be read from guacamole.properties. + */ + public Integer getPeriod() throws GuacamoleException { + + // Do not reveal code period unless enrollment is in progress + if (key == null) + return null; + + return confService.getPeriod(); + + } + + /** + * Returns the "otpauth" URI for the secret key used to generate TOTP codes + * for the current user. If the secret key is not being exposed to + * facilitate enrollment, null is returned. + * + * @return + * The "otpauth" URI for the secret key used to generate TOTP codes + * for the current user, or null is the secret ket is not being exposed + * to facilitate enrollment. + * + * @throws GuacamoleException + * If the configuration information required for generating the key URI + * cannot be read from guacamole.properties. + */ + @JsonProperty("keyUri") + public URI getKeyURI() throws GuacamoleException { + + // Do not generate a key URI if no key is being exposed + if (key == null) + return null; + + // Format "otpauth" URL (see https://github.com/google/google-authenticator/wiki/Key-Uri-Format) + String issuer = confService.getIssuer(); + return UriBuilder.fromUri("otpauth://totp/") + .path(issuer + ":" + key.getUsername()) + .queryParam("secret", BASE32.encode(key.getSecret())) + .queryParam("issuer", issuer) + .queryParam("algorithm", confService.getMode()) + .queryParam("digits", confService.getDigits()) + .queryParam("period", confService.getPeriod()) + .build(); + + } + + /** + * Returns the URL of a QR code describing the user's TOTP key and + * configuration. If the key is not being exposed for enrollment, null is + * returned. + * + * @return + * The URL of a QR code describing the user's TOTP key and + * configuration, or null if the key is not being exposed for + * enrollment. + * + * @throws GuacamoleException + * If the configuration information required for generating the QR code + * cannot be read from guacamole.properties. + */ + @JsonProperty("qrCode") + public String getQRCode() throws GuacamoleException { + + // Do not generate a QR code if no key is being exposed + URI keyURI = getKeyURI(); + if (keyURI == null) + return null; + + ByteArrayOutputStream stream = new ByteArrayOutputStream(); + + try { + + // Create QR code writer + QRCodeWriter writer = new QRCodeWriter(); + BitMatrix matrix = writer.encode(keyURI.toString(), + BarcodeFormat.QR_CODE, QR_CODE_WIDTH, QR_CODE_HEIGHT); + + // Produce PNG image of TOTP key text + MatrixToImageWriter.writeToStream(matrix, "PNG", stream); + + } + catch (WriterException e) { + throw new IllegalArgumentException("QR code could not be " + + "generated for TOTP key.", e); + } + catch (IOException e) { + throw new IllegalStateException("Image stream of QR code could " + + "not be written.", e); + } + + // Return data URI for generated image + return "data:image/png;base64," + + DatatypeConverter.printBase64Binary(stream.toByteArray()); + + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/CodeUsageTrackingService.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/CodeUsageTrackingService.java new file mode 100644 index 000000000..c9a94b4b5 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/CodeUsageTrackingService.java @@ -0,0 +1,264 @@ +/* + * 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.totp.user; + +import com.google.inject.Inject; +import com.google.inject.Singleton; +import java.util.Iterator; +import java.util.Map; +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; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.auth.totp.conf.ConfigurationService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Service for tracking past valid uses of TOTP codes. An internal thread + * periodically walks through records of past codes, removing records which + * should be invalid by their own nature (no longer matching codes generated by + * the secret key). + */ +@Singleton +public class CodeUsageTrackingService { + + /** + * The number of periods during which a previously-used code should remain + * unusable. Once this period has elapsed, the code can be reused again if + * it is otherwise valid. + */ + private static final int INVALID_INTERVAL = 2; + + /** + * Logger for this class. + */ + private final Logger logger = LoggerFactory.getLogger(CodeUsageTrackingService.class); + + /** + * Executor service which runs the cleanup task. + */ + private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1); + + /** + * Service for retrieving configuration information. + */ + @Inject + private ConfigurationService confService; + + /** + * Map of previously-used codes to the timestamp after which the code can + * be used again, providing the TOTP key legitimately generates that code. + */ + private final ConcurrentMap invalidCodes = + new ConcurrentHashMap(); + + /** + * Creates a new CodeUsageTrackingService which tracks past valid uses of + * TOTP codes on a per-user basis. + */ + public CodeUsageTrackingService() { + executor.scheduleAtFixedRate(new CodeEvictionTask(), 1, 1, TimeUnit.MINUTES); + } + + /** + * Task which iterates through all explicitly-invalidated codes, evicting + * those codes which are old enough that they would fail validation against + * the secret key anyway. + */ + private class CodeEvictionTask implements Runnable { + + @Override + public void run() { + + // Get start time of cleanup check + long checkStart = System.currentTimeMillis(); + + // For each code still being tracked, remove those which are old + // enough that they would fail validation against the secret key + Iterator> entries = invalidCodes.entrySet().iterator(); + while (entries.hasNext()) { + + Map.Entry entry = entries.next(); + long invalidUntil = entry.getValue(); + + // If code is sufficiently old, evict it and check the next one + if (checkStart >= invalidUntil) + entries.remove(); + + } + + // Log completion and duration + logger.debug("TOTP tracking cleanup check completed in {} ms.", + System.currentTimeMillis() - checkStart); + + } + + } + + /** + * A valid TOTP code which was previously used by a particular user. + */ + private class UsedCode { + + /** + * The username of the user which previously used this code. + */ + private final String username; + + /** + * The valid code given by the user. + */ + private final String code; + + /** + * Creates a new UsedCode which records the given code as having been + * used by the given user. + * + * @param username + * The username of the user which previously used the given code. + * + * @param code + * The valid code given by the user. + */ + public UsedCode(String username, String code) { + this.username = username; + this.code = code; + } + + /** + * Returns the username of the user which previously used the code + * associated with this UsedCode. + * + * @return + * The username of the user which previously used this code. + */ + public String getUsername() { + return username; + } + + /** + * Returns the valid code given by the user when this UsedCode was + * created. + * + * @return + * The valid code given by the user. + */ + public String getCode() { + return code; + } + + @Override + public int hashCode() { + int hash = 7; + hash = 79 * hash + this.username.hashCode(); + hash = 79 * hash + this.code.hashCode(); + return hash; + } + + @Override + public boolean equals(Object obj) { + + if (this == obj) + return true; + + if (obj == null) + return false; + + if (getClass() != obj.getClass()) + return false; + + final UsedCode other = (UsedCode) obj; + return username.equals(other.username) && code.equals(other.code); + + } + + } + + /** + * Attempts to mark the given code as used. The code MUST have already been + * validated against the user's secret key, as this function only verifies + * whether the code has been previously used, not whether it is actually + * valid. If the code has not previously been used, the code is stored as + * having been used by the given user at the current time. + * + * @param username + * The username of the user who has attempted to use the given valid + * code. + * + * @param code + * The otherwise-valid code given by the user. + * + * @return + * true if the code has not previously been used by the given user and + * has now been marked as previously used, false otherwise. + * + * @throws GuacamoleException + * If configuration information necessary to determine the length of + * time a code should be marked as invalid cannot be read from + * guacamole.properties. + */ + public boolean useCode(String username, String code) + throws GuacamoleException { + + // Repeatedly attempt to use the given code until an explicit success + // or failure has occurred + UsedCode usedCode = new UsedCode(username, code); + for (;;) { + + // Explicitly invalidate each used code for two periods after its + // first successful use + long current = System.currentTimeMillis(); + long invalidUntil = current + confService.getPeriod() * 1000 * INVALID_INTERVAL; + + // Try to use the given code, marking it as used within the map of + // now-invalidated codes + Long expires = invalidCodes.putIfAbsent(usedCode, invalidUntil); + if (expires == null) + return true; + + // If the code was already used, fail to use the code if + // insufficient time has elapsed since it was last used + // successfully + if (expires > current) + return false; + + + // Otherwise, the code is actually valid - remove the invalidated + // code only if it still has the expected expiration time, and + // retry using the code + invalidCodes.remove(usedCode, expires); + + } + + } + + /** + * Cleans up resources which may be in use by this service in the + * background, such as other threads. This function MUST be invoked during + * webapp shutdown to avoid leaking these resources. + */ + public void shutdown() { + executor.shutdownNow(); + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/TOTPUser.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/TOTPUser.java new file mode 100644 index 000000000..4199d4380 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/TOTPUser.java @@ -0,0 +1,102 @@ +/* + * 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.totp.user; + +import java.util.HashMap; +import java.util.Map; +import org.apache.guacamole.net.auth.DelegatingUser; +import org.apache.guacamole.net.auth.User; + +/** + * TOTP-specific User implementation which wraps a User from another extension, + * hiding and blocking access to the core attributes used by TOTP. + */ +public class TOTPUser extends DelegatingUser { + + /** + * The name of the user attribute which stores the TOTP key. + */ + public static final String TOTP_KEY_SECRET_ATTRIBUTE_NAME = "guac-totp-key-secret"; + + /** + * The name of the user attribute defines whether the TOTP key has been + * confirmed by the user, and the user is thus fully enrolled. + */ + public static final String TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME = "guac-totp-key-confirmed"; + + /** + * The User object wrapped by this TOTPUser. + */ + private final User undecorated; + + /** + * Wraps the given User object, hiding and blocking access to the core + * attributes used by TOTP. + * + * @param user + * The User object to wrap. + */ + public TOTPUser(User user) { + super(user); + this.undecorated = user; + } + + /** + * Returns the User object wrapped by this TOTPUser. + * + * @return + * The wrapped User object. + */ + public User getUndecorated() { + return undecorated; + } + + @Override + public Map getAttributes() { + + // Create independent, mutable copy of attributes + Map attributes = + new HashMap(super.getAttributes()); + + // Do not expose any TOTP-related attributes outside this extension + attributes.remove(TOTP_KEY_SECRET_ATTRIBUTE_NAME); + attributes.remove(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME); + + // Expose only non-TOTP attributes + return attributes; + + } + + @Override + public void setAttributes(Map attributes) { + + // Create independent, mutable copy of attributes + attributes = new HashMap(attributes); + + // Do not expose any TOTP-related attributes outside this extension + attributes.remove(TOTP_KEY_SECRET_ATTRIBUTE_NAME); + attributes.remove(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME); + + // Set only non-TOTP attributes + super.setAttributes(attributes); + + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/TOTPUserContext.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/TOTPUserContext.java new file mode 100644 index 000000000..980bbf782 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/TOTPUserContext.java @@ -0,0 +1,64 @@ +/* + * 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.totp.user; + +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.net.auth.DecoratingDirectory; +import org.apache.guacamole.net.auth.DelegatingUserContext; +import org.apache.guacamole.net.auth.Directory; +import org.apache.guacamole.net.auth.User; +import org.apache.guacamole.net.auth.UserContext; + +/** + * TOTP-specific UserContext implementation which wraps the UserContext of + * some other extension, providing (or hiding) additional data. + */ +public class TOTPUserContext extends DelegatingUserContext { + + /** + * Creates a new TOTPUserContext which wraps the given UserContext, + * providing (or hiding) additional TOTP-specific data. + * + * @param userContext + * The UserContext to wrap. + */ + public TOTPUserContext(UserContext userContext) { + super(userContext); + } + + @Override + public Directory getUserDirectory() throws GuacamoleException { + return new DecoratingDirectory(super.getUserDirectory()) { + + @Override + protected User decorate(User object) { + return new TOTPUser(object); + } + + @Override + protected User undecorate(User object) { + assert(object instanceof TOTPUser); + return ((TOTPUser) object).getUndecorated(); + } + + }; + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserTOTPKey.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserTOTPKey.java new file mode 100644 index 000000000..d7bc903e7 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserTOTPKey.java @@ -0,0 +1,148 @@ +/* + * 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.totp.user; + +import java.security.SecureRandom; +import java.util.Random; + +/** + * The key used to generate TOTP codes for a particular user. + */ +public class UserTOTPKey { + + /** + * Secure source of random bytes. + */ + private static final Random RANDOM = new SecureRandom(); + + /** + * The username of the user associated with this key. + */ + private final String username; + + /** + * Whether the associated secret key has been confirmed by the user. A key + * is confirmed once the user has successfully entered a valid TOTP + * derived from that key. + */ + private boolean confirmed; + + /** + * The base32-encoded TOTP key associated with the user. + */ + private byte[] secret; + + /** + * Generates the given number of random bytes. + * + * @param length + * The number of random bytes to generate. + * + * @return + * A new array of exactly the given number of random bytes. + */ + private static byte[] generateBytes(int length) { + byte[] bytes = new byte[length]; + RANDOM.nextBytes(bytes); + return bytes; + } + + /** + * Creates a new, unconfirmed, randomly-generated TOTP key having the given + * length. + * + * @param username + * The username of the user associated with this key. + * + * @param length + * The length of the key to generate, in bytes. + */ + public UserTOTPKey(String username, int length) { + this(username, generateBytes(length), false); + } + + /** + * Creates a new UserTOTPKey containing the given key and having the given + * confirmed state. + * + * @param username + * The username of the user associated with this key. + * + * @param secret + * The raw binary secret key to be used to generate TOTP codes. + * + * @param confirmed + * true if the user associated with the key has confirmed that they can + * successfully generate the corresponding TOTP codes (the user has + * been "enrolled"), false otherwise. + */ + public UserTOTPKey(String username, byte[] secret, boolean confirmed) { + this.username = username; + this.confirmed = confirmed; + this.secret = secret; + } + + /** + * Returns the username of the user associated with this key. + * + * @return + * The username of the user associated with this key. + */ + public String getUsername() { + return username; + } + + /** + * Returns the raw binary secret key to be used to generate TOTP codes. + * + * @return + * The raw binary secret key to be used to generate TOTP codes. + */ + public byte[] getSecret() { + return secret; + } + + /** + * Returns whether the user associated with the key has confirmed that they + * can successfully generate the corresponding TOTP codes (the user has + * been "enrolled"). + * + * @return + * true if the user has confirmed that they can successfully generate + * the TOTP codes generated by this key, false otherwise. + */ + public boolean isConfirmed() { + return confirmed; + } + + /** + * Sets whether the user associated with the key has confirmed that they + * can successfully generate the corresponding TOTP codes (the user has + * been "enrolled"). + * + * @param confirmed + * true if the user has confirmed that they can successfully generate + * the TOTP codes generated by this key, false otherwise. + */ + public void setConfirmed(boolean confirmed) { + this.confirmed = confirmed; + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java new file mode 100644 index 000000000..30108e1c6 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/auth/totp/user/UserVerificationService.java @@ -0,0 +1,288 @@ +/* + * 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.totp.user; + +import com.google.common.io.BaseEncoding; +import com.google.inject.Inject; +import com.google.inject.Provider; +import java.security.InvalidKeyException; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import javax.servlet.http.HttpServletRequest; +import org.apache.guacamole.GuacamoleClientException; +import org.apache.guacamole.GuacamoleException; +import org.apache.guacamole.GuacamoleUnsupportedException; +import org.apache.guacamole.auth.totp.conf.ConfigurationService; +import org.apache.guacamole.auth.totp.form.AuthenticationCodeField; +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.User; +import org.apache.guacamole.net.auth.UserContext; +import org.apache.guacamole.net.auth.credentials.CredentialsInfo; +import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException; +import org.apache.guacamole.totp.TOTPGenerator; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Service for verifying the identity of a user using TOTP. + */ +public class UserVerificationService { + + /** + * Logger for this class. + */ + private final Logger logger = LoggerFactory.getLogger(UserVerificationService.class); + + /** + * BaseEncoding instance which decoded/encodes base32. + */ + private static final BaseEncoding BASE32 = BaseEncoding.base32(); + + /** + * Service for retrieving configuration information. + */ + @Inject + private ConfigurationService confService; + + /** + * Service for tracking whether TOTP codes have been used. + */ + @Inject + private CodeUsageTrackingService codeService; + + /** + * Provider for AuthenticationCodeField instances. + */ + @Inject + private Provider codeFieldProvider; + + /** + * Retrieves and decodes the base32-encoded TOTP key associated with user + * having the given UserContext. If no TOTP key is associated with the user, + * a random key is generated and associated with the user. If the extension + * storing the user does not support storage of the TOTP key, null is + * returned. + * + * @param context + * The UserContext of the user whose TOTP key should be retrieved. + * + * @param username + * The username of the user associated with the given UserContext. + * + * @return + * The TOTP key associated with the user having the given UserContext, + * or null if the extension storing the user does not support storage + * of the TOTP key. + * + * @throws GuacamoleException + * If a new key is generated, but the extension storing the associated + * user fails while updating the user account. + */ + private UserTOTPKey getKey(UserContext context, + String username) throws GuacamoleException { + + // Retrieve attributes from current user + User self = context.self(); + Map attributes = context.self().getAttributes(); + + // If no key is defined, attempt to generate a new key + String secret = attributes.get(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME); + if (secret == null) { + + // Generate random key for user + TOTPGenerator.Mode mode = confService.getMode(); + UserTOTPKey generated = new UserTOTPKey(username,mode.getRecommendedKeyLength()); + if (setKey(context, generated)) + return generated; + + // Fail if key cannot be set + return null; + + } + + // Parse retrieved base32 key value + byte[] key; + try { + key = BASE32.decode(secret); + } + + // If key is not valid base32, warn but otherwise pretend the key does + // not exist + catch (IllegalArgumentException e) { + logger.warn("TOTP key of user \"{}\" is not valid base32.", self.getIdentifier()); + logger.debug("TOTP key is not valid base32.", e); + return null; + } + + // Otherwise, parse value from attributes + boolean confirmed = "true".equals(attributes.get(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME)); + return new UserTOTPKey(username, key, confirmed); + + } + + /** + * Attempts to store the given TOTP key within the user account of the user + * having the given UserContext. As not all extensions will support storage + * of arbitrary attributes, this operation may fail. + * + * @param context + * The UserContext associated with the user whose TOTP key is to be + * stored. + * + * @param key + * The TOTP key to store. + * + * @return + * true if the TOTP key was successfully stored, false if the extension + * handling storage does not support storage of the key. + * + * @throws GuacamoleException + * If the extension handling storage fails internally while attempting + * to update the user. + */ + private boolean setKey(UserContext context, UserTOTPKey key) + throws GuacamoleException { + + // Get mutable set of attributes + User self = context.self(); + Map attributes = new HashMap(); + + // Set/overwrite current TOTP key state + attributes.put(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME, BASE32.encode(key.getSecret())); + attributes.put(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME, key.isConfirmed() ? "true" : "false"); + self.setAttributes(attributes); + + // Confirm that attributes have actually been set + Map setAttributes = self.getAttributes(); + if (!setAttributes.containsKey(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME) + || !setAttributes.containsKey(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME)) + return false; + + // Update user object + try { + context.getUserDirectory().update(self); + } + catch (GuacamoleUnsupportedException e) { + logger.debug("Extension storage for user is explicitly read-only. " + + "Cannot update attributes to store TOTP key.", e); + return false; + } + + // TOTP key successfully stored/updated + return true; + + } + + /** + * Verifies the identity of the given user using TOTP. If a authentication + * code from the user's TOTP device has not already been provided, a code is + * requested in the form of additional expected credentials. Any provided + * code is cryptographically verified. If no code is present, or the + * received code is invalid, an exception is thrown. + * + * @param context + * The UserContext provided for the user by another authentication + * extension. + * + * @param authenticatedUser + * The user whose identity should be verified using TOTP. + * + * @throws GuacamoleException + * If required TOTP-specific configuration options are missing or + * malformed, or if the user's identity cannot be verified. + */ + public void verifyIdentity(UserContext context, + AuthenticatedUser authenticatedUser) throws GuacamoleException { + + // Ignore anonymous users + String username = authenticatedUser.getIdentifier(); + if (username.equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER)) + return; + + // Ignore users which do not have an associated key + UserTOTPKey key = getKey(context, username); + if (key == null) + return; + + // Pull the original HTTP request used to authenticate + Credentials credentials = authenticatedUser.getCredentials(); + HttpServletRequest request = credentials.getRequest(); + + // Retrieve TOTP from request + String code = request.getParameter(AuthenticationCodeField.PARAMETER_NAME); + + // If no TOTP provided, request one + if (code == null) { + + AuthenticationCodeField field = codeFieldProvider.get(); + + // If the user hasn't completed enrollment, request that they do + if (!key.isConfirmed()) { + field.exposeKey(key); + throw new GuacamoleInsufficientCredentialsException( + "TOTP.INFO_ENROLL_REQUIRED", new CredentialsInfo( + Collections.singletonList(field) + )); + } + + // Otherwise simply request the user's authentication code + throw new GuacamoleInsufficientCredentialsException( + "TOTP.INFO_CODE_REQUIRED", new CredentialsInfo( + Collections.singletonList(field) + )); + + } + + try { + + // Get generator based on user's key and provided configuration + TOTPGenerator totp = new TOTPGenerator(key.getSecret(), + confService.getMode(), confService.getDigits()); + + // Verify provided TOTP against value produced by generator + if ((code.equals(totp.generate()) || code.equals(totp.previous())) + && codeService.useCode(username, code)) { + + // Record key as confirmed, if it hasn't already been so recorded + if (!key.isConfirmed()) { + key.setConfirmed(true); + setKey(context, key); + } + + // User has been verified + return; + + } + + } + catch (InvalidKeyException e) { + logger.warn("User \"{}\" is associated with an invalid TOTP key.", username); + logger.debug("TOTP key is not valid.", e); + } + + // Provided code is not valid + throw new GuacamoleClientException("TOTP.INFO_VERIFICATION_FAILED"); + + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/totp/TOTPGenerator.java b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/totp/TOTPGenerator.java new file mode 100644 index 000000000..d075c8afc --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/java/org/apache/guacamole/totp/TOTPGenerator.java @@ -0,0 +1,456 @@ +/* + * 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.totp; + +import com.google.common.primitives.Longs; +import java.security.InvalidKeyException; +import java.security.Key; +import java.security.NoSuchAlgorithmException; +import javax.crypto.Mac; +import javax.crypto.spec.SecretKeySpec; + +/* + * NOTE: This TOTP implementation is based on the TOTP reference implementation + * provided by the IETF Trust at: + * + * https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl + */ + +/* + * Copyright (c) 2011 IETF Trust and the persons identified as authors + * of the code. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Internet Society, IETF or IETF Trust, nor the names + * of specific contributors, may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 OWNER 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. + */ + +/** + * Generator which uses the TOTP algorithm to generate authentication codes. + */ +public class TOTPGenerator { + + /** + * The default time to use as the basis for comparison when transforming + * provided TOTP timestamps into counter values required for HOTP, in + * seconds since midnight, 1970-01-01, UTC (UNIX epoch). + */ + public static final long DEFAULT_START_TIME = 0; + + /** + * The default frequency at which new TOTP codes should be generated (and + * old codes invalidated), in seconds. + */ + public static final long DEFAULT_TIME_STEP = 30; + + /** + * The TOTP generation mode. The mode dictates the hash function which + * should be used to generate authentication codes, as well as the required + * key size. + */ + private final Mode mode; + + /** + * The shared key to use to generate authentication codes. The size + * required for this key depends on the generation mode. + */ + private final Key key; + + /** + * The length of codes to generate, in digits. + */ + private final int length; + + /** + * The base time against which the timestamp specified for each TOTP + * should be compared to produce the corresponding HOTP counter value, in + * seconds since midnight, 1970-01-01, UTC (UNIX epoch). This is the value + * value referred to as "T0" in the TOTP specification. + */ + private final long startTime; + + /** + * The frequency that new TOTP codes should be generated and invalidated, + * in seconds. This is the value referred to as "X" in the TOTP + * specification. + */ + private final long timeStep; + + /** + * The operating mode for TOTP, defining the hash algorithm to be used. + */ + public enum Mode { + + /** + * TOTP mode which generates hashes using SHA1. TOTP in SHA1 mode + * requires 160-bit keys. + */ + SHA1("HmacSHA1", 20), + + /** + * TOTP mode which generates hashes using SHA256. TOTP in SHA256 mode + * requires 256-bit keys. + */ + SHA256("HmacSHA256", 32), + + /** + * TOTP mode which generates hashes using SHA512. TOTP in SHA512 mode + * requires 512-bit keys. + */ + SHA512("HmacSHA512", 64); + + /** + * The name of the HMAC algorithm which the TOTP implementation should + * use when operating in this mode, in the format required by + * Mac.getInstance(). + */ + private final String algorithmName; + + /** + * The recommended length of keys generated for TOTP in this mode, in + * bytes. Keys are recommended to be the same length as the hash + * involved. + */ + private final int recommendedKeyLength; + + /** + * Creates a new TOTP operating mode which is associated with the + * given HMAC algorithm. + * + * @param algorithmName + * The name of the HMAC algorithm which the TOTP implementation + * should use when operating in this mode, in the format required + * by Mac.getInstance(). + * + * @param recommendedKeyLength + * The recommended length of keys generated for TOTP in this mode, + * in bytes. + */ + private Mode(String algorithmName, int recommendedKeyLength) { + this.algorithmName = algorithmName; + this.recommendedKeyLength = recommendedKeyLength; + } + + /** + * Returns the name of the HMAC algorithm which the TOTP implementation + * should use when operating in this mode. The name returned will be + * in the format required by Mac.getInstance(). + * + * @return + * The name of the HMAC algorithm which the TOTP implementation + * should use. + */ + public String getAlgorithmName() { + return algorithmName; + } + + /** + * Returns the recommended length of keys generated for TOTP in this + * mode, in bytes. Keys are recommended to be the same length as the + * hash involved. + * + * @return + * The recommended length of keys generated for TOTP in this mode, + * in bytes. + */ + public int getRecommendedKeyLength() { + return recommendedKeyLength; + } + + } + + /** + * Creates a new TOTP generator which uses the given shared key to generate + * authentication codes. The provided generation mode dictates the size of + * the key required, while the given start time and time step dictate how + * timestamps provided for code generation are converted to the counter + * value used by HOTP (the algorithm which forms the basis of TOTP). + * + * @param key + * The shared key to use to generate authentication codes. + * + * @param mode + * The mode in which the TOTP algorithm should operate. + * + * @param length + * The length of the codes to generate, in digits. As required + * by the specification, this value MUST be at least 6 but no greater + * than 8. + * + * @param startTime + * The base time against which the timestamp specified for each TOTP + * should be compared to produce the corresponding HOTP counter value, + * in seconds since midnight, 1970-01-01, UTC (UNIX epoch). This is the + * value referred to as "T0" in the TOTP specification. + * + * @param timeStep + * The frequency that new TOTP codes should be generated and + * invalidated, in seconds. This is the value referred to as "X" in the + * TOTP specification. + * + * @throws InvalidKeyException + * If the provided key is invalid for the requested TOTP mode. + */ + public TOTPGenerator(byte[] key, Mode mode, int length, long startTime, + long timeStep) throws InvalidKeyException { + + // Validate length is within spec + if (length < 6 || length > 8) + throw new IllegalArgumentException("TOTP codes must be at least 6 " + + "digits and no more than 8 digits."); + + this.key = new SecretKeySpec(key, "RAW"); + this.mode = mode; + this.length = length; + this.startTime = startTime; + this.timeStep = timeStep; + + // Verify key validity + getMacInstance(this.mode, this.key); + + } + + /** + * Creates a new TOTP generator which uses the given shared key to generate + * authentication codes. The provided generation mode dictates the size of + * the key required. The start time and time step used to produce the + * counter value used by HOTP (the algorithm which forms the basis of TOTP) + * are set to the default values recommended by the TOTP specification (0 + * and 30 respectively). + * + * @param key + * The shared key to use to generate authentication codes. + * + * @param mode + * The mode in which the TOTP algorithm should operate. + * + * @param length + * The length of the codes to generate, in digits. As required + * by the specification, this value MUST be at least 6 but no greater + * than 8. + * + * @throws InvalidKeyException + * If the provided key is invalid for the requested TOTP mode. + */ + public TOTPGenerator(byte[] key, Mode mode, int length) + throws InvalidKeyException { + this(key, mode, length, DEFAULT_START_TIME, DEFAULT_TIME_STEP); + } + + /** + * Returns a new Mac instance which produces message authentication codes + * using the given secret key and the algorithm required by the given TOTP + * mode. + * + * @param mode + * The TOTP mode which dictates the HMAC algorithm to be used. + * + * @param key + * The secret key to use to produce message authentication codes. + * + * @return + * A new Mac instance which produces message authentication codes + * using the given secret key and the algorithm required by the given + * TOTP mode. + * + * @throws InvalidKeyException + * If the provided key is invalid for the requested TOTP mode. + */ + private static Mac getMacInstance(Mode mode, Key key) + throws InvalidKeyException { + + try { + Mac hmac = Mac.getInstance(mode.getAlgorithmName()); + hmac.init(key); + return hmac; + } + catch (NoSuchAlgorithmException e) { + throw new UnsupportedOperationException("Support for the HMAC " + + "algorithm required for TOTP in " + mode + " mode is " + + "missing.", e); + } + + } + + /** + * Calculates the HMAC for the given message using the key and algorithm + * provided when this TOTPGenerator was created. + * + * @param message + * The message to calculate the HMAC of. + * + * @return + * The HMAC of the given message. + */ + private byte[] getHMAC(byte[] message) { + + try { + return getMacInstance(mode, key).doFinal(message); + } + catch (InvalidKeyException e) { + + // As the key is verified during construction of the TOTPGenerator, + // this should never happen + throw new IllegalStateException("Provided key became invalid after " + + "passing validation.", e); + + } + + } + + /** + * Given an arbitrary integer value, returns a code containing the decimal + * representation of that value and exactly the given number of digits. If + * the given value has more than the desired number of digits, leading + * digits will be truncated to reduce the length. If the given value has + * fewer than the desired number of digits, leading zeroes will be added to + * increase the length. + * + * @param value + * The value to convert into a decimal code of the given length. + * + * @param length + * The number of digits to include in the code. + * + * @return + * A code containing the decimal value of the given integer, truncated + * or padded such that exactly the given number of digits are present. + */ + private String toCode(int value, int length) { + + // Convert value to simple integer string + String valueString = Integer.toString(value); + + // If the resulting string is too long, truncate to the last N digits + if (valueString.length() > length) + return valueString.substring(valueString.length() - length); + + // Otherwise, add zeroes until the desired length is reached + StringBuilder builder = new StringBuilder(length); + for (int i = valueString.length(); i < length; i++) + builder.append('0'); + + // Return the padded integer string + builder.append(valueString); + return builder.toString(); + + } + + /** + * Generates a TOTP code of the given length using the given absolute + * timestamp rather than the current system time. + * + * @param time + * The absolute timestamp to use to generate the TOTP code, in seconds + * since midnight, 1970-01-01, UTC (UNIX epoch). + * + * @return + * The TOTP code which corresponds to the given timestamp, having + * exactly the given length. + * + * @throws IllegalArgumentException + * If the given length is invalid as defined by the TOTP specification. + */ + public String generate(long time) { + + // Calculate HOTP counter value based on provided time + long counter = (time - startTime) / timeStep; + byte[] hash = getHMAC(Longs.toByteArray(counter)); + + // Calculate HOTP value as defined by section 5.2 of RFC 4226: + // https://tools.ietf.org/html/rfc4226#section-5.2 + int offset = hash[hash.length - 1] & 0xF; + int binary + = ((hash[offset] & 0x7F) << 24) + | ((hash[offset + 1] & 0xFF) << 16) + | ((hash[offset + 2] & 0xFF) << 8) + | (hash[offset + 3] & 0xFF); + + // Truncate or pad the value accordingly + return toCode(binary, length); + + } + + /** + * Generates a TOTP code of the given length using the current system time. + * + * @return + * The TOTP code which corresponds to the current system time, having + * exactly the given length. + * + * @throws IllegalArgumentException + * If the given length is invalid as defined by the TOTP specification. + */ + public String generate() { + return generate(System.currentTimeMillis() / 1000); + } + + /** + * Returns the TOTP code which would have been generated immediately prior + * to the code returned by invoking generate() with the given timestamp. + * + * @param time + * The absolute timestamp to use to generate the TOTP code, in seconds + * since midnight, 1970-01-01, UTC (UNIX epoch). + * + * @return + * The TOTP code which would have been generated immediately prior to + * the the code returned by invoking generate() with the given + * timestamp. + */ + public String previous(long time) { + return generate(Math.max(startTime, time - timeStep)); + } + + /** + * Returns the TOTP code which would have been generated immediately prior + * to the code currently being returned by generate(). + * + * @return + * The TOTP code which would have been generated immediately prior to + * the code currently being returned by generate(). + */ + public String previous() { + return previous(System.currentTimeMillis() / 1000); + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/resources/config/totpConfig.js b/extensions/guacamole-auth-totp/src/main/resources/config/totpConfig.js new file mode 100644 index 000000000..54bb56c08 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/resources/config/totpConfig.js @@ -0,0 +1,33 @@ +/* + * 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. + */ + +/** + * Config block which registers TOTP-specific field types. + */ +angular.module('guacTOTP').config(['formServiceProvider', + function guacTOTPConfig(formServiceProvider) { + + // Define field for the TOTP code provided by the user + formServiceProvider.registerFieldType('GUAC_TOTP_CODE', { + module : 'guacTOTP', + controller : 'authenticationCodeFieldController', + templateUrl : 'app/ext/totp/templates/authenticationCodeField.html' + }); + +}]); diff --git a/extensions/guacamole-auth-totp/src/main/resources/controllers/authenticationCodeFieldController.js b/extensions/guacamole-auth-totp/src/main/resources/controllers/authenticationCodeFieldController.js new file mode 100644 index 000000000..8f19c9f6c --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/resources/controllers/authenticationCodeFieldController.js @@ -0,0 +1,68 @@ +/* + * 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. + */ + +/** + * Controller for the "GUAC_TOTP_CODE" field which prompts the user to enter + * the code generated by their authentication device. + */ +angular.module('guacTOTP').controller('authenticationCodeFieldController', ['$scope', '$window', + function authenticationCodeFieldController($scope, $window) { + + /** + * The secret key split into groups of at most four characters each, or + * null if the secret key is not exposed. + * + * @type String[] + */ + $scope.groupedSecret = $scope.field.secret && $scope.field.secret.match(/.{1,4}/g); + + /** + * Whether the raw details of the secret key and TOTP configuration should + * be shown. By default, such details are hidden. If the secret key is not + * exposed, this property has no effect. + */ + $scope.detailsShown = false; + + /** + * Shows the raw details of the secret key and TOTP configuration. If the + * secret key is not exposed, or the details are already shown, this + * function has no effect. + */ + $scope.showDetails = function showDetails() { + $scope.detailsShown = true; + }; + + /** + * Hides the raw details of the secret key and TOTP configuration. If the + * details are already hidden, this function has no effect. + */ + $scope.hideDetails = function hideDetails() { + $scope.detailsShown = false; + }; + + /** + * Attempts to open the "otpauth" URI containing the user's TOTP key, + * invoking whichever application may be installed locally for handling + * multi-factor authentication. + */ + $scope.openKeyURI = function openKeyURI() { + $window.open($scope.field.keyUri); + }; + +}]); diff --git a/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json new file mode 100644 index 000000000..dee829170 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/resources/guac-manifest.json @@ -0,0 +1,28 @@ +{ + + "guacamoleVersion" : "0.9.14", + + "name" : "TOTP TFA Authentication Backend", + "namespace" : "totp", + + "authProviders" : [ + "org.apache.guacamole.auth.totp.TOTPAuthenticationProvider" + ], + + "translations" : [ + "translations/en.json" + ], + + "js" : [ + "totp.min.js" + ], + + "css" : [ + "totp.min.css" + ], + + "resources" : { + "templates/authenticationCodeField.html" : "text/html" + } + +} diff --git a/extensions/guacamole-auth-totp/src/main/resources/license.txt b/extensions/guacamole-auth-totp/src/main/resources/license.txt new file mode 100644 index 000000000..042f3ce1f --- /dev/null +++ b/extensions/guacamole-auth-totp/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-totp/src/main/resources/styles/totp.css b/extensions/guacamole-auth-totp/src/main/resources/styles/totp.css new file mode 100644 index 000000000..c8a250534 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/resources/styles/totp.css @@ -0,0 +1,88 @@ +/* + * 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. + */ + +.totp-enroll p, .totp-details { + font-size: 0.8em; +} + +.totp-qr-code { + text-align: center; +} + +.totp-qr-code img { + margin: 1em; + border: 1px solid rgba(0,0,0,0.25); + box-shadow: 1px 1px 2px rgba(0,0,0,0.25); + cursor: pointer; +} + +h3.totp-details-header { + font-size: 0.8em; +} + +h3.totp-details-header::before { + content: '▸ '; +} + +.totp-details-visible h3.totp-details-header::before { + content: '▾ '; +} + +.totp-details, +.totp-hide-details { + display: none; +} + +.totp-details-visible .totp-details { + display: table; +} + +.totp-details-visible .totp-hide-details { + display: inline; +} + +.totp-details-visible .totp-show-details { + display: none; +} + +.totp-hide-details, .totp-show-details { + color: blue; + text-decoration: underline; + cursor: pointer; + margin: 0 0.25em; + font-weight: normal; +} + +.totp-details { + margin: 0 auto; +} + +.totp-details th { + padding-right: 0.25em; + text-align: left; +} + +.totp-details td { + font-family: monospace; +} + +.totp-detail { + display: inline-block; + margin: 0 0.25em; +} diff --git a/extensions/guacamole-auth-totp/src/main/resources/templates/authenticationCodeField.html b/extensions/guacamole-auth-totp/src/main/resources/templates/authenticationCodeField.html new file mode 100644 index 000000000..c493a2050 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/resources/templates/authenticationCodeField.html @@ -0,0 +1,47 @@ +
+ + +
+ +

+ + +
+

+ {{'TOTP.SECTION_HEADER_DETAILS' | translate}} + {{'TOTP.ACTION_SHOW_DETAILS' | translate}} + {{'TOTP.ACTION_HIDE_DETAILS' | translate}} +

+ + + + + + + + + + + + + + + + + +
{{'TOTP.FIELD_HEADER_SECRET_KEY' | translate}}{{ group }}
{{'TOTP.FIELD_HEADER_DIGITS' | translate}}{{ field.digits }}
{{'TOTP.FIELD_HEADER_ALGORITHM' | translate}}{{ field.mode }}
{{'TOTP.FIELD_HEADER_INTERVAL' | translate}}{{ field.period }}
+ +

+ +
+ + +
+ +
+ +
diff --git a/extensions/guacamole-auth-totp/src/main/resources/totpModule.js b/extensions/guacamole-auth-totp/src/main/resources/totpModule.js new file mode 100644 index 000000000..c6a0c7ea4 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/resources/totpModule.js @@ -0,0 +1,28 @@ +/* + * 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. + */ + +/** + * Module which provides handling for TOTP multi-factor authentication. + */ +angular.module('guacTOTP', [ + 'form' +]); + +// Ensure the guacTOTP module is loaded along with the rest of the app +angular.module('index').requires.push('guacTOTP'); diff --git a/extensions/guacamole-auth-totp/src/main/resources/translations/en.json b/extensions/guacamole-auth-totp/src/main/resources/translations/en.json new file mode 100644 index 000000000..6f73aa02d --- /dev/null +++ b/extensions/guacamole-auth-totp/src/main/resources/translations/en.json @@ -0,0 +1,34 @@ +{ + + "DATA_SOURCE_TOTP" : { + "NAME" : "TOTP TFA Backend" + }, + + "LOGIN" : { + "FIELD_HEADER_GUAC_TOTP" : "" + }, + + "TOTP" : { + + "ACTION_HIDE_DETAILS" : "Hide", + "ACTION_SHOW_DETAILS" : "Show", + + "FIELD_HEADER_ALGORITHM" : "Algorithm:", + "FIELD_HEADER_DIGITS" : "Digits:", + "FIELD_HEADER_INTERVAL" : "Interval:", + "FIELD_HEADER_SECRET_KEY" : "Secret Key:", + + "FIELD_PLACEHOLDER_CODE" : "Authentication Code", + + "INFO_CODE_REQUIRED" : "Please enter your authentication code to verify your identity.", + "INFO_ENROLL_REQUIRED" : "Multi-factor authentication has been enabled on your account.", + "INFO_VERIFICATION_FAILED" : "Verification failed. Please try again.", + + "HELP_ENROLL_BARCODE" : "To complete the enrollment process, scan the barcode below with the two-factor authentication app on your phone or device.", + "HELP_ENROLL_VERIFY" : "After scanning the barcode, enter the {DIGITS}-digit authentication code displayed to verify that enrollment was successful.", + + "SECTION_HEADER_DETAILS" : "Details:" + + } + +} diff --git a/extensions/guacamole-auth-totp/src/test/java/org/apache/guacamole/totp/TOTPGeneratorTest.java b/extensions/guacamole-auth-totp/src/test/java/org/apache/guacamole/totp/TOTPGeneratorTest.java new file mode 100644 index 000000000..9266ad7e3 --- /dev/null +++ b/extensions/guacamole-auth-totp/src/test/java/org/apache/guacamole/totp/TOTPGeneratorTest.java @@ -0,0 +1,168 @@ +/* + * 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.totp; + +import java.security.InvalidKeyException; +import org.junit.Test; +import static org.junit.Assert.*; + +/* + * NOTE: The tests for this TOTP implementation is based on the TOTP reference + * implementation provided by the IETF Trust at: + * + * https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl + */ + +/* + * Copyright (c) 2011 IETF Trust and the persons identified as authors + * of the code. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * - Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * + * - 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. + * + * - Neither the name of Internet Society, IETF or IETF Trust, nor the names + * of specific contributors, may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 OWNER 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. + */ + +/** + * Test which verifies the correctness of the TOTPGenerator class against the + * test inputs and results provided in the IETF reference implementation and + * spec for TOTP: + * + * https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Test-Vectors + */ +public class TOTPGeneratorTest { + + /** + * Verifies the results of generating authentication codes using the TOTP + * algorithm in SHA1 mode. + */ + @Test + public void testGenerateSHA1() { + + // 160-bit key consisting of the bytes "12345678901234567890" repeated + // as necessary + final byte[] key = { + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0' + }; + + try { + final TOTPGenerator totp = new TOTPGenerator(key, TOTPGenerator.Mode.SHA1, 8); + assertEquals("94287082", totp.generate(59)); + assertEquals("07081804", totp.generate(1111111109)); + assertEquals("14050471", totp.generate(1111111111)); + assertEquals("89005924", totp.generate(1234567890)); + assertEquals("69279037", totp.generate(2000000000)); + assertEquals("65353130", totp.generate(20000000000L)); + } + catch (InvalidKeyException e) { + fail("SHA1 test key is invalid."); + } + + + } + + /** + * Verifies the results of generating authentication codes using the TOTP + * algorithm in SHA256 mode. + */ + @Test + public void testGenerateSHA256() { + + // 256-bit key consisting of the bytes "12345678901234567890" repeated + // as necessary + final byte[] key = { + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2' + }; + + try { + final TOTPGenerator totp = new TOTPGenerator(key, TOTPGenerator.Mode.SHA256, 8); + assertEquals("46119246", totp.generate(59)); + assertEquals("68084774", totp.generate(1111111109)); + assertEquals("67062674", totp.generate(1111111111)); + assertEquals("91819424", totp.generate(1234567890)); + assertEquals("90698825", totp.generate(2000000000)); + assertEquals("77737706", totp.generate(20000000000L)); + } + catch (InvalidKeyException e) { + fail("SHA256 test key is invalid."); + } + + } + + /** + * Verifies the results of generating authentication codes using the TOTP + * algorithm in SHA512 mode. + */ + @Test + public void testGenerateSHA512() { + + // 512-bit key consisting of the bytes "12345678901234567890" repeated + // as necessary + final byte[] key = { + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', + '1', '2', '3', '4' + }; + + try { + final TOTPGenerator totp = new TOTPGenerator(key, TOTPGenerator.Mode.SHA512, 8); + assertEquals("90693936", totp.generate(59)); + assertEquals("25091201", totp.generate(1111111109)); + assertEquals("99943326", totp.generate(1111111111)); + assertEquals("93441116", totp.generate(1234567890)); + assertEquals("38618901", totp.generate(2000000000)); + assertEquals("47863826", totp.generate(20000000000L)); + } + catch (InvalidKeyException e) { + fail("SHA512 test key is invalid."); + } + + } + +} diff --git a/guacamole/src/main/webapp/app/login/styles/login.css b/guacamole/src/main/webapp/app/login/styles/login.css index 17078274c..4cb07f18a 100644 --- a/guacamole/src/main/webapp/app/login/styles/login.css +++ b/guacamole/src/main/webapp/app/login/styles/login.css @@ -20,7 +20,7 @@ div.login-ui { height: 100%; width: 100%; - position: fixed; + position: absolute; left: 0; top: 0; display: table; diff --git a/pom.xml b/pom.xml index 59cff02e2..4f7c8ed6a 100644 --- a/pom.xml +++ b/pom.xml @@ -55,6 +55,7 @@ extensions/guacamole-auth-jdbc extensions/guacamole-auth-ldap extensions/guacamole-auth-openid + extensions/guacamole-auth-totp doc/guacamole-example