diff --git a/extensions/guacamole-auth-openid/.gitignore b/extensions/guacamole-auth-openid/.gitignore
new file mode 100644
index 000000000..30eb48707
--- /dev/null
+++ b/extensions/guacamole-auth-openid/.gitignore
@@ -0,0 +1,3 @@
+*~
+target/
+src/main/resources/generated/
diff --git a/extensions/guacamole-auth-openid/pom.xml b/extensions/guacamole-auth-openid/pom.xml
new file mode 100644
index 000000000..4076998f1
--- /dev/null
+++ b/extensions/guacamole-auth-openid/pom.xml
@@ -0,0 +1,252 @@
+
+
+
+
+ 4.0.0
+ org.apache.guacamole
+ guacamole-auth-openid
+ jar
+ 0.9.13-incubating
+ guacamole-auth-openid
+ 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/guac-openid
+
+
+
+
+
+ com.samaxes.maven
+ minify-maven-plugin
+ 1.7.5
+
+
+ default-cli
+
+ UTF-8
+
+ ${basedir}/src/main/resources
+ ${project.build.directory}/classes
+
+ /
+ /
+ openid.css
+
+
+ license.txt
+
+
+
+ **/*.css
+
+
+ /
+ /
+ openid.js
+
+
+ license.txt
+
+
+
+ **/*.js
+
+
+
+
+ **/*.test.js
+
+ CLOSURE
+
+
+
+ OFF
+ OFF
+
+
+
+
+ minify
+
+
+
+
+
+
+
+ org.apache.maven.plugins
+ maven-dependency-plugin
+ 2.10
+
+
+ unpack-dependencies
+ prepare-package
+
+ unpack-dependencies
+
+
+ runtime
+ ${project.build.directory}/classes
+
+
+
+
+
+
+
+ maven-assembly-plugin
+ 2.5.3
+
+ ${project.artifactId}-${project.version}
+ false
+
+ src/main/assembly/dist.xml
+
+
+
+
+ make-dist-archive
+ package
+
+ single
+
+
+
+
+
+
+
+ org.apache.rat
+ apache-rat-plugin
+ 0.12
+
+
+
+ **/*.json
+ src/licenses/**/*
+ src/main/resources/templates/*.html
+
+
+
+
+
+
+ validate
+ validate
+
+ check
+
+
+
+
+
+
+
+
+
+
+
+
+
+ org.apache.guacamole
+ guacamole-ext
+ 0.9.13-incubating
+ provided
+
+
+
+
+ org.bitbucket.b_c
+ jose4j
+ 0.5.5
+
+
+ org.slf4j
+ slf4j-api
+
+
+
+
+
+
+ com.google.inject
+ guice
+ 3.0
+
+
+ com.google.inject.extensions
+ guice-multibindings
+ 3.0
+
+
+
+
+ javax.servlet
+ servlet-api
+ 2.5
+ provided
+
+
+
+
+
diff --git a/extensions/guacamole-auth-openid/src/licenses/DISCLAIMER b/extensions/guacamole-auth-openid/src/licenses/DISCLAIMER
new file mode 100644
index 000000000..1a9c3be8d
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/licenses/DISCLAIMER
@@ -0,0 +1,7 @@
+Apache Guacamole is an effort undergoing incubation at The Apache Software
+Foundation (ASF). Incubation is required of all newly accepted projects until a
+further review indicates that the infrastructure, communications, and decision
+making process have stabilized in a manner consistent with other successful ASF
+projects. While incubation status is not necessarily a reflection of the
+completeness or stability of the code, it does indicate that the project has
+yet to be fully endorsed by the ASF.
diff --git a/extensions/guacamole-auth-openid/src/licenses/LICENSE b/extensions/guacamole-auth-openid/src/licenses/LICENSE
new file mode 100644
index 000000000..f95ed290f
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/licenses/LICENSE
@@ -0,0 +1,248 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+
+
+==============================================================================
+
+APACHE GUACAMOLE SUBCOMPONENTS
+
+Apache Guacamole includes a number of subcomponents with separate copyright
+notices and license terms. Your use of these subcomponents is subject to the
+terms and conditions of the following licenses.
+
+
+AOP Alliance (http://aopalliance.sourceforge.net/)
+--------------------------------------------------
+
+ Version: 1.0
+ From: 'AOP Alliance' (http://aopalliance.sourceforge.net/members.html)
+ License(s):
+ Public Domain (bundled/aopalliance-1.0/LICENSE)
+
+
+Google Guice (https://github.com/google/guice)
+----------------------------------------------
+
+ Version: 3.0
+ From: 'Google Inc.' (http://www.google.com/)
+ License(s):
+ Apache v2.0 (bundled/guice-3.0/COPYING)
+
+
+jose.4.j (https://bitbucket.org/b_c/jose4j/)
+--------------------------------------------
+
+ Version: 0.5.5
+ From: 'Brian Campbell' (https://bitbucket.org/b_c/)
+ License(s):
+ Apache v2.0 (bundled/jose4j-0.5.5/LICENSE)
+
+
+JSR-330 / Dependency Injection for Java (http://code.google.com/p/atinject/)
+----------------------------------------------------------------------------
+
+ Version: 1
+ From: 'JSR-330 Expert Group' (https://jcp.org/en/jsr/detail?id=330)
+ License(s):
+ Apache v2.0 (bundled/javax.inject-1/LICENSE-2.0.txt)
+
diff --git a/extensions/guacamole-auth-openid/src/licenses/NOTICE b/extensions/guacamole-auth-openid/src/licenses/NOTICE
new file mode 100644
index 000000000..2ef7e548b
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/licenses/NOTICE
@@ -0,0 +1,5 @@
+Apache Guacamole
+Copyright 2016 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/extensions/guacamole-auth-openid/src/licenses/bundled/README b/extensions/guacamole-auth-openid/src/licenses/bundled/README
new file mode 100644
index 000000000..47ba19db0
--- /dev/null
+++ b/extensions/guacamole-auth-openid/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-openid/src/licenses/bundled/aopalliance-1.0/LICENSE b/extensions/guacamole-auth-openid/src/licenses/bundled/aopalliance-1.0/LICENSE
new file mode 100644
index 000000000..8e0e3786b
--- /dev/null
+++ b/extensions/guacamole-auth-openid/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-openid/src/licenses/bundled/guice-3.0/COPYING b/extensions/guacamole-auth-openid/src/licenses/bundled/guice-3.0/COPYING
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/extensions/guacamole-auth-openid/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-openid/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt b/extensions/guacamole-auth-openid/src/licenses/bundled/javax.inject-1/LICENSE-2.0.txt
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/extensions/guacamole-auth-openid/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-openid/src/licenses/bundled/jose4j-0.5.5/LICENSE b/extensions/guacamole-auth-openid/src/licenses/bundled/jose4j-0.5.5/LICENSE
new file mode 100644
index 000000000..d64569567
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/licenses/bundled/jose4j-0.5.5/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
diff --git a/extensions/guacamole-auth-openid/src/licenses/bundled/jose4j-0.5.5/NOTICE.txt b/extensions/guacamole-auth-openid/src/licenses/bundled/jose4j-0.5.5/NOTICE.txt
new file mode 100644
index 000000000..46498244b
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/licenses/bundled/jose4j-0.5.5/NOTICE.txt
@@ -0,0 +1,14 @@
+jose4j
+Copyright 2012-2015 Brian Campbell
+
+EcdsaUsingShaAlgorithm contains code for converting the concatenated
+R & S values of the signature to and from DER, which was originally
+derived from the Apache Santuario XML Security library's SignatureECDSA
+implementation. http://santuario.apache.org/
+
+The Base64 implementation in this software was derived from the
+Apache Commons Codec project. http://commons.apache.org/proper/commons-codec/
+
+JSON processing in this software was derived from the JSON.simple toolkit.
+https://code.google.com/p/json-simple/
+
diff --git a/extensions/guacamole-auth-openid/src/main/assembly/dist.xml b/extensions/guacamole-auth-openid/src/main/assembly/dist.xml
new file mode 100644
index 000000000..b89fd534c
--- /dev/null
+++ b/extensions/guacamole-auth-openid/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-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java
new file mode 100644
index 000000000..47d99fff6
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/AuthenticationProviderService.java
@@ -0,0 +1,132 @@
+/*
+ * 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.openid;
+
+import com.google.inject.Inject;
+import com.google.inject.Provider;
+import java.util.Arrays;
+import javax.servlet.http.HttpServletRequest;
+import org.apache.guacamole.auth.openid.conf.ConfigurationService;
+import org.apache.guacamole.auth.openid.form.TokenField;
+import org.apache.guacamole.auth.openid.token.NonceService;
+import org.apache.guacamole.auth.openid.token.TokenValidationService;
+import org.apache.guacamole.auth.openid.user.AuthenticatedUser;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.form.Field;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
+import org.apache.guacamole.net.auth.credentials.GuacamoleInvalidCredentialsException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Service providing convenience functions for the OpenID AuthenticationProvider
+ * implementation.
+ */
+public class AuthenticationProviderService {
+
+ /**
+ * Logger for this class.
+ */
+ private final Logger logger = LoggerFactory.getLogger(AuthenticationProviderService.class);
+
+ /**
+ * Service for retrieving OpenID configuration information.
+ */
+ @Inject
+ private ConfigurationService confService;
+
+ /**
+ * Service for validating and generating unique nonce values.
+ */
+ @Inject
+ private NonceService nonceService;
+
+ /**
+ * Service for validating received ID tokens.
+ */
+ @Inject
+ private TokenValidationService tokenService;
+
+ /**
+ * Provider for AuthenticatedUser objects.
+ */
+ @Inject
+ private Provider authenticatedUserProvider;
+
+ /**
+ * Returns an AuthenticatedUser representing the user authenticated by the
+ * given credentials.
+ *
+ * @param credentials
+ * The credentials to use for authentication.
+ *
+ * @return
+ * An AuthenticatedUser representing the user authenticated by the
+ * given credentials.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while authenticating the user, or if access is
+ * denied.
+ */
+ public AuthenticatedUser authenticateUser(Credentials credentials)
+ throws GuacamoleException {
+
+ String username = null;
+
+ // Validate OpenID token in request, if present, and derive username
+ HttpServletRequest request = credentials.getRequest();
+ if (request != null) {
+ String token = request.getParameter(TokenField.PARAMETER_NAME);
+ if (token != null)
+ username = tokenService.processUsername(token);
+ }
+
+ // If the username was successfully retrieved from the token, produce
+ // authenticated user
+ if (username != null) {
+
+ // Create corresponding authenticated user
+ AuthenticatedUser authenticatedUser = authenticatedUserProvider.get();
+ authenticatedUser.init(username, credentials);
+ return authenticatedUser;
+
+ }
+
+ // Request OpenID token
+ throw new GuacamoleInvalidCredentialsException("Invalid login.",
+ new CredentialsInfo(Arrays.asList(new Field[] {
+
+ // OpenID-specific token (will automatically redirect the user
+ // to the authorization page via JavaScript)
+ new TokenField(
+ confService.getAuthorizationEndpoint(),
+ confService.getScope(),
+ confService.getClientID(),
+ confService.getRedirectURI(),
+ nonceService.generate(confService.getMaxNonceValidity() * 60000L)
+ )
+
+ }))
+ );
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProvider.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProvider.java
new file mode 100644
index 000000000..57b483183
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProvider.java
@@ -0,0 +1,115 @@
+/*
+ * 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.openid;
+
+import com.google.inject.Guice;
+import com.google.inject.Injector;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.net.auth.AuthenticatedUser;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.auth.Credentials;
+import org.apache.guacamole.net.auth.UserContext;
+
+/**
+ * Guacamole authentication backend which authenticates users using an
+ * arbitrary external system implementing OpenID. No storage for connections is
+ * provided - only authentication. Storage must be provided by some other
+ * extension.
+ */
+public class OpenIDAuthenticationProvider implements AuthenticationProvider {
+
+ /**
+ * Injector which will manage the object graph of this authentication
+ * provider.
+ */
+ private final Injector injector;
+
+ /**
+ * Creates a new OpenIDAuthenticationProvider that authenticates users
+ * against an OpenID service.
+ *
+ * @throws GuacamoleException
+ * If a required property is missing, or an error occurs while parsing
+ * a property.
+ */
+ public OpenIDAuthenticationProvider() throws GuacamoleException {
+
+ // Set up Guice injector.
+ injector = Guice.createInjector(
+ new OpenIDAuthenticationProviderModule(this)
+ );
+
+ }
+
+ @Override
+ public String getIdentifier() {
+ return "openid";
+ }
+
+ @Override
+ public Object getResource() throws GuacamoleException {
+ return null;
+ }
+
+ @Override
+ public AuthenticatedUser authenticateUser(Credentials credentials)
+ throws GuacamoleException {
+
+ // Attempt to authenticate user with given credentials
+ AuthenticationProviderService authProviderService = injector.getInstance(AuthenticationProviderService.class);
+ return authProviderService.authenticateUser(credentials);
+
+ }
+
+ @Override
+ public AuthenticatedUser updateAuthenticatedUser(
+ AuthenticatedUser authenticatedUser, Credentials credentials)
+ throws GuacamoleException {
+
+ // No update necessary
+ return authenticatedUser;
+
+ }
+
+ @Override
+ public UserContext getUserContext(AuthenticatedUser authenticatedUser)
+ throws GuacamoleException {
+
+ // No associated data whatsoever
+ return null;
+
+ }
+
+ @Override
+ public UserContext updateUserContext(UserContext context,
+ AuthenticatedUser authenticatedUser, Credentials credentials)
+ throws GuacamoleException {
+
+ // No update necessary
+ return context;
+
+ }
+
+ @Override
+ public void shutdown() {
+ // Do nothing
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProviderModule.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProviderModule.java
new file mode 100644
index 000000000..17510cbe5
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/OpenIDAuthenticationProviderModule.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.openid;
+
+import com.google.inject.AbstractModule;
+import org.apache.guacamole.auth.openid.conf.ConfigurationService;
+import org.apache.guacamole.auth.openid.token.NonceService;
+import org.apache.guacamole.auth.openid.token.TokenValidationService;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.environment.LocalEnvironment;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+
+/**
+ * Guice module which configures openid-specific injections.
+ */
+public class OpenIDAuthenticationProviderModule extends AbstractModule {
+
+ /**
+ * Guacamole server environment.
+ */
+ private final Environment environment;
+
+ /**
+ * A reference to the OpenIDAuthenticationProvider on behalf of which this
+ * module has configured injection.
+ */
+ private final AuthenticationProvider authProvider;
+
+ /**
+ * Creates a new OpenID authentication provider module which configures
+ * injection for the OpenIDAuthenticationProvider.
+ *
+ * @param authProvider
+ * The AuthenticationProvider for which injection is being configured.
+ *
+ * @throws GuacamoleException
+ * If an error occurs while retrieving the Guacamole server
+ * environment.
+ */
+ public OpenIDAuthenticationProviderModule(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 openid-specific services
+ bind(ConfigurationService.class);
+ bind(NonceService.class);
+ bind(TokenValidationService.class);
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java
new file mode 100644
index 000000000..c742d8991
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/conf/ConfigurationService.java
@@ -0,0 +1,362 @@
+/*
+ * 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.openid.conf;
+
+import com.google.inject.Inject;
+import org.apache.guacamole.GuacamoleException;
+import org.apache.guacamole.environment.Environment;
+import org.apache.guacamole.properties.IntegerGuacamoleProperty;
+import org.apache.guacamole.properties.StringGuacamoleProperty;
+
+/**
+ * Service for retrieving configuration information regarding the OpenID
+ * service.
+ */
+public class ConfigurationService {
+
+ /**
+ * The default claim type to use to retrieve an authenticated user's
+ * username.
+ */
+ private static final String DEFAULT_USERNAME_CLAIM_TYPE = "email";
+
+ /**
+ * The default space-separated list of OpenID scopes to request.
+ */
+ private static final String DEFAULT_SCOPE = "openid email profile";
+
+ /**
+ * The default amount of clock skew tolerated for timestamp comparisons
+ * between the Guacamole server and OpenID service clocks, in seconds.
+ */
+ private static final int DEFAULT_ALLOWED_CLOCK_SKEW = 30;
+
+ /**
+ * The default maximum amount of time that an OpenID token should remain
+ * valid, in minutes.
+ */
+ private static final int DEFAULT_MAX_TOKEN_VALIDITY = 300;
+
+ /**
+ * The default maximum amount of time that a nonce generated by the
+ * Guacamole server should remain valid, in minutes.
+ */
+ private static final int DEFAULT_MAX_NONCE_VALIDITY = 10;
+
+ /**
+ * The authorization endpoint (URI) of the OpenID service.
+ */
+ private static final StringGuacamoleProperty OPENID_AUTHORIZATION_ENDPOINT =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-authorization-endpoint"; }
+
+ };
+
+ /**
+ * The endpoint (URI) of the JWKS service which defines how received ID
+ * tokens (JWTs) shall be validated.
+ */
+ private static final StringGuacamoleProperty OPENID_JWKS_ENDPOINT =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-jwks-endpoint"; }
+
+ };
+
+ /**
+ * The issuer to expect for all received ID tokens.
+ */
+ private static final StringGuacamoleProperty OPENID_ISSUER =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-issuer"; }
+
+ };
+
+ /**
+ * The claim type which contains the authenticated user's username within
+ * any valid JWT.
+ */
+ private static final StringGuacamoleProperty OPENID_USERNAME_CLAIM_TYPE =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-username-claim-type"; }
+
+ };
+
+ /**
+ * The space-separated list of OpenID scopes to request.
+ */
+ private static final StringGuacamoleProperty OPENID_SCOPE =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-scope"; }
+
+ };
+
+ /**
+ * The amount of clock skew tolerated for timestamp comparisons between the
+ * Guacamole server and OpenID service clocks, in seconds.
+ */
+ private static final IntegerGuacamoleProperty OPENID_ALLOWED_CLOCK_SKEW =
+ new IntegerGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-allowed-clock-skew"; }
+
+ };
+
+ /**
+ * The maximum amount of time that an OpenID token should remain valid, in
+ * minutes.
+ */
+ private static final IntegerGuacamoleProperty OPENID_MAX_TOKEN_VALIDITY =
+ new IntegerGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-max-token-validity"; }
+
+ };
+
+ /**
+ * The maximum amount of time that a nonce generated by the Guacamole server
+ * should remain valid, in minutes. As each OpenID request has a unique
+ * nonce value, this imposes an upper limit on the amount of time any
+ * particular OpenID request can result in successful authentication within
+ * Guacamole.
+ */
+ private static final IntegerGuacamoleProperty OPENID_MAX_NONCE_VALIDITY =
+ new IntegerGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-max-nonce-validity"; }
+
+ };
+
+ /**
+ * OpenID client ID which should be submitted to the OpenID service when
+ * necessary. This value is typically provided by the OpenID service when
+ * OpenID credentials are generated for your application.
+ */
+ private static final StringGuacamoleProperty OPENID_CLIENT_ID =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-client-id"; }
+
+ };
+
+ /**
+ * The URI that the OpenID service should redirect to after the
+ * authentication process is complete. This must be the full URL that a
+ * user would enter into their browser to access Guacamole.
+ */
+ private static final StringGuacamoleProperty OPENID_REDIRECT_URI =
+ new StringGuacamoleProperty() {
+
+ @Override
+ public String getName() { return "openid-redirect-uri"; }
+
+ };
+
+ /**
+ * The Guacamole server environment.
+ */
+ @Inject
+ private Environment environment;
+
+ /**
+ * Returns the authorization endpoint (URI) of the OpenID service as
+ * configured with guacamole.properties.
+ *
+ * @return
+ * The authorization endpoint of the OpenID service, as configured with
+ * guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed, or if the authorization
+ * endpoint property is missing.
+ */
+ public String getAuthorizationEndpoint() throws GuacamoleException {
+ return environment.getRequiredProperty(OPENID_AUTHORIZATION_ENDPOINT);
+ }
+
+ /**
+ * Returns the OpenID client ID which should be submitted to the OpenID
+ * service when necessary, as configured with guacamole.properties. This
+ * value is typically provided by the OpenID service when OpenID credentials
+ * are generated for your application.
+ *
+ * @return
+ * The client ID to use when communicating with the OpenID service,
+ * as configured with guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed, or if the client ID
+ * property is missing.
+ */
+ public String getClientID() throws GuacamoleException {
+ return environment.getRequiredProperty(OPENID_CLIENT_ID);
+ }
+
+ /**
+ * Returns the URI that the OpenID service should redirect to after
+ * the authentication process is complete, as configured with
+ * guacamole.properties. This must be the full URL that a user would enter
+ * into their browser to access Guacamole.
+ *
+ * @return
+ * The client secret to use when communicating with the OpenID service,
+ * as configured with guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed, or if the redirect URI
+ * property is missing.
+ */
+ public String getRedirectURI() throws GuacamoleException {
+ return environment.getRequiredProperty(OPENID_REDIRECT_URI);
+ }
+
+ /**
+ * Returns the issuer to expect for all received ID tokens, as configured
+ * with guacamole.properties.
+ *
+ * @return
+ * The issuer to expect for all received ID tokens, as configured with
+ * guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed, or if the issuer property
+ * is missing.
+ */
+ public String getIssuer() throws GuacamoleException {
+ return environment.getRequiredProperty(OPENID_ISSUER);
+ }
+
+ /**
+ * Returns the endpoint (URI) of the JWKS service which defines how
+ * received ID tokens (JWTs) shall be validated, as configured with
+ * guacamole.properties.
+ *
+ * @return
+ * The endpoint (URI) of the JWKS service which defines how received ID
+ * tokens (JWTs) shall be validated, as configured with
+ * guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed, or if the JWKS endpoint
+ * property is missing.
+ */
+ public String getJWKSEndpoint() throws GuacamoleException {
+ return environment.getRequiredProperty(OPENID_JWKS_ENDPOINT);
+ }
+
+ /**
+ * Returns the claim type which contains the authenticated user's username
+ * within any valid JWT, as configured with guacamole.properties. By
+ * default, this will be "email".
+ *
+ * @return
+ * The claim type which contains the authenticated user's username
+ * within any valid JWT, as configured with guacamole.properties.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public String getUsernameClaimType() throws GuacamoleException {
+ return environment.getProperty(OPENID_USERNAME_CLAIM_TYPE, DEFAULT_USERNAME_CLAIM_TYPE);
+ }
+
+ /**
+ * Returns the space-separated list of OpenID scopes to request. By default,
+ * this will be "openid email profile". The OpenID scopes determine the
+ * information returned within the OpenID token, and thus affect what
+ * values can be used as an authenticated user's username.
+ *
+ * @return
+ * The space-separated list of OpenID scopes to request when identifying
+ * a user.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public String getScope() throws GuacamoleException {
+ return environment.getProperty(OPENID_SCOPE, DEFAULT_SCOPE);
+ }
+
+ /**
+ * Returns the amount of clock skew tolerated for timestamp comparisons
+ * between the Guacamole server and OpenID service clocks, in seconds. Too
+ * much clock skew will affect token expiration calculations, possibly
+ * allowing old tokens to be used. By default, this will be 30.
+ *
+ * @return
+ * The amount of clock skew tolerated for timestamp comparisons, in
+ * seconds.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public int getAllowedClockSkew() throws GuacamoleException {
+ return environment.getProperty(OPENID_ALLOWED_CLOCK_SKEW, DEFAULT_ALLOWED_CLOCK_SKEW);
+ }
+
+ /**
+ * Returns the maximum amount of time that an OpenID token should remain
+ * valid, in minutes. A token received from an OpenID service which is
+ * older than this amount of time will be rejected, even if it is otherwise
+ * valid. By default, this will be 300 (5 hours).
+ *
+ * @return
+ * The maximum amount of time that an OpenID token should remain valid,
+ * in minutes.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public int getMaxTokenValidity() throws GuacamoleException {
+ return environment.getProperty(OPENID_MAX_TOKEN_VALIDITY, DEFAULT_MAX_TOKEN_VALIDITY);
+ }
+
+ /**
+ * Returns the maximum amount of time that a nonce generated by the
+ * Guacamole server should remain valid, in minutes. As each OpenID request
+ * has a unique nonce value, this imposes an upper limit on the amount of
+ * time any particular OpenID request can result in successful
+ * authentication within Guacamole. By default, this will be 10.
+ *
+ * @return
+ * The maximum amount of time that a nonce generated by the Guacamole
+ * server should remain valid, in minutes.
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties cannot be parsed.
+ */
+ public int getMaxNonceValidity() throws GuacamoleException {
+ return environment.getProperty(OPENID_MAX_NONCE_VALIDITY, DEFAULT_MAX_NONCE_VALIDITY);
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java
new file mode 100644
index 000000000..d99c3672d
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/form/TokenField.java
@@ -0,0 +1,106 @@
+/*
+ * 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.openid.form;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import org.apache.guacamole.form.Field;
+
+/**
+ * Field definition which represents the token returned by an OpenID Connect
+ * service.
+ */
+public class TokenField extends Field {
+
+ /**
+ * The standard HTTP parameter which will be included within the URL by all
+ * OpenID services upon successful authentication and redirect.
+ */
+ public static final String PARAMETER_NAME = "id_token";
+
+ /**
+ * The full URI which the field should link to.
+ */
+ private final String authorizationURI;
+
+ /**
+ * Creates a new field which requests authentication via OpenID connect.
+ * Successful authentication at the OpenID Connect service will result in
+ * the client being redirected to the specified redirect URI. The OpenID
+ * token will be embedded in the fragment (the part following the hash
+ * symbol) of that URI, which the JavaScript side of this extension will
+ * move to the query parameters.
+ *
+ * @param authorizationEndpoint
+ * The full URL of the endpoint accepting OpenID authentication
+ * requests.
+ *
+ * @param scope
+ * The space-delimited list of OpenID scopes to request from the
+ * identity provider, such as "openid" or "openid email profile".
+ *
+ * @param clientID
+ * The ID of the OpenID client. This is normally determined ahead of
+ * time by the OpenID service through some manual credential request
+ * procedure.
+ *
+ * @param redirectURI
+ * The URI that the OpenID service should redirect to upon successful
+ * authentication.
+ *
+ * @param nonce
+ * A random string unique to this request. To defend against replay
+ * attacks, this value must cease being valid after its first use.
+ */
+ public TokenField(String authorizationEndpoint, String scope,
+ String clientID, String redirectURI, String nonce) {
+
+ // Init base field properties
+ super(PARAMETER_NAME, "GUAC_OPENID_TOKEN");
+
+ // Build authorization URI from given values
+ try {
+ this.authorizationURI = authorizationEndpoint
+ + "?scope=" + URLEncoder.encode(scope, "UTF-8")
+ + "&response_type=id_token"
+ + "&client_id=" + URLEncoder.encode(clientID, "UTF-8")
+ + "&redirect_uri=" + URLEncoder.encode(redirectURI, "UTF-8")
+ + "&nonce=" + nonce;
+ }
+
+ // Java is required to provide UTF-8 support
+ catch (UnsupportedEncodingException e) {
+ throw new UnsupportedOperationException("Unexpected lack of UTF-8 support.", e);
+ }
+
+ }
+
+ /**
+ * Returns the full URI that this field should link to when a new token
+ * needs to be obtained from the OpenID service.
+ *
+ * @return
+ * The full URI that this field should link to.
+ */
+ public String getAuthorizationURI() {
+ return authorizationURI;
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/NonceService.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/NonceService.java
new file mode 100644
index 000000000..778112a76
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/NonceService.java
@@ -0,0 +1,135 @@
+/*
+ * 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.openid.token;
+
+import com.google.inject.Singleton;
+import java.math.BigInteger;
+import java.security.SecureRandom;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * Service for generating and validating single-use random tokens (nonces).
+ */
+@Singleton
+public class NonceService {
+
+ /**
+ * Cryptographically-secure random number generator for generating the
+ * required nonce.
+ */
+ private final SecureRandom random = new SecureRandom();
+
+ /**
+ * Map of all generated nonces to their corresponding expiration timestamps.
+ * This Map must be periodically swept of expired nonces to avoid growing
+ * without bound.
+ */
+ private final Map nonces = new ConcurrentHashMap();
+
+ /**
+ * The timestamp of the last expired nonce sweep.
+ */
+ private long lastSweep = System.currentTimeMillis();
+
+ /**
+ * The minimum amount of time to wait between sweeping expired nonces from
+ * the Map.
+ */
+ private static final long SWEEP_INTERVAL = 60000;
+
+ /**
+ * Iterates through the entire Map of generated nonces, removing any nonce
+ * that has exceeded its expiration timestamp. If insufficient time has
+ * elapsed since the last sweep, as dictated by SWEEP_INTERVAL, this
+ * function has no effect.
+ */
+ private void sweepExpiredNonces() {
+
+ // Do not sweep until enough time has elapsed since the last sweep
+ long currentTime = System.currentTimeMillis();
+ if (currentTime - lastSweep < SWEEP_INTERVAL)
+ return;
+
+ // Record time of sweep
+ lastSweep = currentTime;
+
+ // For each stored nonce
+ Iterator> entries = nonces.entrySet().iterator();
+ while (entries.hasNext()) {
+
+ // Remove all entries which have expired
+ Map.Entry current = entries.next();
+ if (current.getValue() <= System.currentTimeMillis())
+ entries.remove();
+
+ }
+
+ }
+
+ /**
+ * Generates a cryptographically-secure nonce value. The nonce is intended
+ * to be used to prevent replay attacks.
+ *
+ * @param maxAge
+ * The maximum amount of time that the generated nonce should remain
+ * valid, in milliseconds.
+ *
+ * @return
+ * A cryptographically-secure nonce value.
+ */
+ public String generate(long maxAge) {
+
+ // Sweep expired nonces if enough time has passed
+ sweepExpiredNonces();
+
+ // Generate and store nonce, along with expiration timestamp
+ String nonce = new BigInteger(130, random).toString(32);
+ nonces.put(nonce, System.currentTimeMillis() + maxAge);
+ return nonce;
+
+ }
+
+ /**
+ * Returns whether the give nonce value is valid. A nonce is valid if and
+ * only if it was generated by this instance of the NonceService. Testing
+ * nonce validity through this function immediately and permanently
+ * invalidates that nonce.
+ *
+ * @param nonce
+ * The nonce value to test.
+ *
+ * @return
+ * true if the provided nonce is valid, false otherwise.
+ */
+ public boolean isValid(String nonce) {
+
+ // Remove nonce, verifying whether it was present at all
+ Long expires = nonces.remove(nonce);
+ if (expires == null)
+ return false;
+
+ // Nonce is only valid if it hasn't expired
+ return expires > System.currentTimeMillis();
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java
new file mode 100644
index 000000000..cde4f89a6
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/token/TokenValidationService.java
@@ -0,0 +1,140 @@
+/*
+ * 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.openid.token;
+
+import com.google.inject.Inject;
+import org.apache.guacamole.auth.openid.conf.ConfigurationService;
+import org.apache.guacamole.GuacamoleException;
+import org.jose4j.jwk.HttpsJwks;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.jwt.MalformedClaimException;
+import org.jose4j.jwt.consumer.InvalidJwtException;
+import org.jose4j.jwt.consumer.JwtConsumer;
+import org.jose4j.jwt.consumer.JwtConsumerBuilder;
+import org.jose4j.keys.resolvers.HttpsJwksVerificationKeyResolver;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Service for validating ID tokens forwarded to us by the client, verifying
+ * that they did indeed come from the OpenID service.
+ */
+public class TokenValidationService {
+
+ /**
+ * Logger for this class.
+ */
+ private final Logger logger = LoggerFactory.getLogger(TokenValidationService.class);
+
+ /**
+ * Service for retrieving OpenID configuration information.
+ */
+ @Inject
+ private ConfigurationService confService;
+
+ /**
+ * Service for validating and generating unique nonce values.
+ */
+ @Inject
+ private NonceService nonceService;
+
+ /**
+ * Validates and parses the given ID token, returning the username contained
+ * therein, as defined by the username claim type given in
+ * guacamole.properties. If the username claim type is missing or the ID
+ * token is invalid, null is returned.
+ *
+ * @param token
+ * The ID token to validate and parse.
+ *
+ * @return
+ * The username contained within the given ID token, or null if the ID
+ * token is not valid or the username claim type is missing,
+ *
+ * @throws GuacamoleException
+ * If guacamole.properties could not be parsed.
+ */
+ public String processUsername(String token) throws GuacamoleException {
+
+ // Validating the token requires a JWKS key resolver
+ HttpsJwks jwks = new HttpsJwks(confService.getJWKSEndpoint());
+ HttpsJwksVerificationKeyResolver resolver = new HttpsJwksVerificationKeyResolver(jwks);
+
+ // Create JWT consumer for validating received token
+ JwtConsumer jwtConsumer = new JwtConsumerBuilder()
+ .setRequireExpirationTime()
+ .setMaxFutureValidityInMinutes(confService.getMaxTokenValidity())
+ .setAllowedClockSkewInSeconds(confService.getAllowedClockSkew())
+ .setRequireSubject()
+ .setExpectedIssuer(confService.getIssuer())
+ .setExpectedAudience(confService.getClientID())
+ .setVerificationKeyResolver(resolver)
+ .build();
+
+ try {
+
+ String usernameClaim = confService.getUsernameClaimType();
+
+ // Validate JWT
+ JwtClaims claims = jwtConsumer.processToClaims(token);
+
+ // Verify a nonce is present
+ String nonce = claims.getStringClaimValue("nonce");
+ if (nonce == null) {
+ logger.info("Rejected OpenID token without nonce.");
+ return null;
+ }
+
+ // Verify that we actually generated the nonce, and that it has not
+ // already been used
+ if (!nonceService.isValid(nonce)) {
+ logger.debug("Rejected OpenID token with invalid/old nonce.");
+ return null;
+ }
+
+ // Pull username from claims
+ String username = claims.getStringClaimValue(usernameClaim);
+ if (username != null)
+ return username;
+
+ // Warn if username was not present in token, as it likely means
+ // the system is not set up correctly
+ logger.warn("Username claim \"{}\" missing from token. Perhaps the "
+ + "OpenID scope and/or username claim type are "
+ + "misconfigured?", usernameClaim);
+
+ }
+
+ // Log any failures to validate/parse the JWT
+ catch (InvalidJwtException e) {
+ logger.info("Rejected invalid OpenID token: {}", e.getMessage());
+ logger.debug("Invalid JWT received.", e);
+ }
+ catch (MalformedClaimException e) {
+ logger.info("Rejected OpenID token with malformed claim: {}", e.getMessage());
+ logger.debug("Malformed claim within received JWT.", e);
+ }
+
+ // Could not retrieve username from JWT
+ return null;
+
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/user/AuthenticatedUser.java b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/user/AuthenticatedUser.java
new file mode 100644
index 000000000..b7ff12549
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/java/org/apache/guacamole/auth/openid/user/AuthenticatedUser.java
@@ -0,0 +1,71 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.guacamole.auth.openid.user;
+
+import com.google.inject.Inject;
+import org.apache.guacamole.net.auth.AbstractAuthenticatedUser;
+import org.apache.guacamole.net.auth.AuthenticationProvider;
+import org.apache.guacamole.net.auth.Credentials;
+
+/**
+ * An openid-specific implementation of AuthenticatedUser, associating a
+ * username and particular set of credentials with the OpenID authentication
+ * provider.
+ */
+public class AuthenticatedUser extends AbstractAuthenticatedUser {
+
+ /**
+ * Reference to the authentication provider associated with this
+ * authenticated user.
+ */
+ @Inject
+ private AuthenticationProvider authProvider;
+
+ /**
+ * The credentials provided when this user was authenticated.
+ */
+ private Credentials credentials;
+
+ /**
+ * Initializes this AuthenticatedUser using the given username and
+ * credentials.
+ *
+ * @param username
+ * The username of the user that was authenticated.
+ *
+ * @param credentials
+ * The credentials provided when this user was authenticated.
+ */
+ public void init(String username, Credentials credentials) {
+ this.credentials = credentials;
+ setIdentifier(username);
+ }
+
+ @Override
+ public AuthenticationProvider getAuthenticationProvider() {
+ return authProvider;
+ }
+
+ @Override
+ public Credentials getCredentials() {
+ return credentials;
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/resources/config/openidConfig.js b/extensions/guacamole-auth-openid/src/main/resources/config/openidConfig.js
new file mode 100644
index 000000000..12bc0dabb
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/resources/config/openidConfig.js
@@ -0,0 +1,54 @@
+/*
+ * 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 openid-specific field types.
+ */
+angular.module('guacOpenID').config(['formServiceProvider',
+ function guacOpenIDConfig(formServiceProvider) {
+
+ // Define field for token from OpenID service
+ formServiceProvider.registerFieldType("GUAC_OPENID_TOKEN", {
+ templateUrl : 'app/ext/guac-openid/templates/openidTokenField.html',
+ controller : 'guacOpenIDController',
+ module : 'guacOpenID'
+ });
+
+}]);
+
+/**
+ * Config block which augments the existing routing, providing special handling
+ * for the "id_token=" fragments provided by OpenID Connect.
+ */
+angular.module('index').config(['$routeProvider',
+ function indexRouteConfig($routeProvider) {
+
+ // Transform "/#/id_token=..." to "/#/?id_token=..."
+ $routeProvider.when('/id_token=:response', {
+
+ template : '',
+ controller : ['$location', function reroute($location) {
+ var params = $location.path().substring(1);
+ $location.url('/');
+ $location.search(params);
+ }]
+
+ });
+
+}]);
diff --git a/extensions/guacamole-auth-openid/src/main/resources/controllers/openidController.js b/extensions/guacamole-auth-openid/src/main/resources/controllers/openidController.js
new file mode 100644
index 000000000..a1fad885c
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/resources/controllers/openidController.js
@@ -0,0 +1,30 @@
+/*
+ * 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_OPENID_TOKEN" field which simply redirects the user
+ * immediately to the authorization URI.
+ */
+angular.module('guacOpenID').controller('guacOpenIDController', ['$scope',
+ function guacOpenIDController($scope) {
+
+ // Redirect to authorization URI
+ window.location = $scope.field.authorizationURI;
+
+}]);
diff --git a/extensions/guacamole-auth-openid/src/main/resources/guac-manifest.json b/extensions/guacamole-auth-openid/src/main/resources/guac-manifest.json
new file mode 100644
index 000000000..e71c140fa
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/resources/guac-manifest.json
@@ -0,0 +1,28 @@
+{
+
+ "guacamoleVersion" : "0.9.13-incubating",
+
+ "name" : "OpenID Authentication Extension",
+ "namespace" : "guac-openid",
+
+ "authProviders" : [
+ "org.apache.guacamole.auth.openid.OpenIDAuthenticationProvider"
+ ],
+
+ "translations" : [
+ "translations/en.json"
+ ],
+
+ "js" : [
+ "openid.min.js"
+ ],
+
+ "css" : [
+ "openid.min.css"
+ ],
+
+ "resources" : {
+ "templates/openidTokenField.html" : "text/html"
+ }
+
+}
diff --git a/extensions/guacamole-auth-openid/src/main/resources/license.txt b/extensions/guacamole-auth-openid/src/main/resources/license.txt
new file mode 100644
index 000000000..042f3ce1f
--- /dev/null
+++ b/extensions/guacamole-auth-openid/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-openid/src/main/resources/openidModule.js b/extensions/guacamole-auth-openid/src/main/resources/openidModule.js
new file mode 100644
index 000000000..e8fce23e2
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/resources/openidModule.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 OpenID authentication.
+ */
+angular.module('guacOpenID', [
+ 'form'
+]);
+
+// Ensure the OpenID module is loaded along with the rest of the app
+angular.module('index').requires.push('guacOpenID');
diff --git a/extensions/guacamole-auth-openid/src/main/resources/styles/openid.css b/extensions/guacamole-auth-openid/src/main/resources/styles/openid.css
new file mode 100644
index 000000000..eab7f935d
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/resources/styles/openid.css
@@ -0,0 +1,35 @@
+/*
+ * 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.
+ */
+
+.openid-token-field-container {
+ height: 100%;
+ width: 100%;
+ position: fixed;
+ left: 0;
+ top: 0;
+ display: table;
+ background: white;
+}
+
+.openid-token-field {
+ width: 100%;
+ display: table-cell;
+ vertical-align: middle;
+ text-align: center;
+}
diff --git a/extensions/guacamole-auth-openid/src/main/resources/templates/openidTokenField.html b/extensions/guacamole-auth-openid/src/main/resources/templates/openidTokenField.html
new file mode 100644
index 000000000..49f6c6f0a
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/resources/templates/openidTokenField.html
@@ -0,0 +1,5 @@
+
+
+
{{ 'LOGIN.INFO_REDIRECT_PENDING' | translate }}
+
+
diff --git a/extensions/guacamole-auth-openid/src/main/resources/translations/en.json b/extensions/guacamole-auth-openid/src/main/resources/translations/en.json
new file mode 100644
index 000000000..6bc52410e
--- /dev/null
+++ b/extensions/guacamole-auth-openid/src/main/resources/translations/en.json
@@ -0,0 +1,12 @@
+{
+
+ "DATA_SOURCE_OPENID" : {
+ "NAME" : "OpenID SSO Backend"
+ },
+
+ "LOGIN" : {
+ "FIELD_HEADER_ID_TOKEN" : "",
+ "INFO_REDIRECT_PENDING" : "Please wait, redirecting to identity provider..."
+ }
+
+}
diff --git a/guacamole/src/main/webapp/app/form/services/formService.js b/guacamole/src/main/webapp/app/form/services/formService.js
index c117bbf7f..64a171310 100644
--- a/guacamole/src/main/webapp/app/form/services/formService.js
+++ b/guacamole/src/main/webapp/app/form/services/formService.js
@@ -244,9 +244,16 @@ angular.module('form').provider('formService', function formServiceProvider() {
}
// If no raw HTML template is provided, retrieve template from URL
- else
+ else if (fieldType.templateUrl)
templateRequest = $templateRequest(fieldType.templateUrl);
+ // Otherwise, use empty template
+ else {
+ var emptyTemplate= $q.defer();
+ emptyTemplate.resolve('');
+ templateRequest = emptyTemplate.promise;
+ }
+
// Defer compilation of template pending successful retrieval
var compiledTemplate = $q.defer();
diff --git a/pom.xml b/pom.xml
index 41317a316..55228f5aa 100644
--- a/pom.xml
+++ b/pom.xml
@@ -55,6 +55,7 @@
extensions/guacamole-auth-jdbcextensions/guacamole-auth-ldapextensions/guacamole-auth-noauth
+ extensions/guacamole-auth-openiddoc/guacamole-example