GUACAMOLE-96: Merge add support for TOTP as an additional authentication factor.

This commit is contained in:
Nick Couchman
2018-02-05 13:02:10 -05:00
35 changed files with 4137 additions and 1 deletions

37
LICENSE
View File

@@ -254,3 +254,40 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
TOTP Reference Implementation (https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl)
-------------------------------------------------------------------------------
Verson: 07
From: 'IETF Trust' (http://trustee.ietf.org/license-info)
License(s):
BSD 3-clause (extensions/guacamole-auth-duo/src/licenses/bundled/totp-reference-impl-07/license.txt)
Copyright (c) 2011 IETF Trust and the persons identified as authors
of the code. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Internet Society, IETF or IETF Trust, nor the names
of specific contributors, may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,3 @@
src/main/resources/generated/
target/
*~

View File

@@ -0,0 +1,274 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-auth-totp</artifactId>
<packaging>jar</packaging>
<version>0.9.14</version>
<name>guacamole-auth-totp</name>
<url>http://guacamole.incubator.apache.org/</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<build>
<plugins>
<!-- Written for 1.6 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<source>1.6</source>
<target>1.6</target>
<compilerArgs>
<arg>-Xlint:all</arg>
<arg>-Werror</arg>
</compilerArgs>
<fork>true</fork>
</configuration>
</plugin>
<!-- Pre-cache Angular templates with maven-angular-plugin -->
<plugin>
<groupId>com.keithbranton.mojo</groupId>
<artifactId>angular-maven-plugin</artifactId>
<version>0.3.2</version>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>html2js</goal>
</goals>
</execution>
</executions>
<configuration>
<sourceDir>${basedir}/src/main/resources</sourceDir>
<include>**/*.html</include>
<target>${basedir}/src/main/resources/generated/templates-main/templates.js</target>
<prefix>app/ext/totp</prefix>
</configuration>
</plugin>
<!-- JS/CSS Minification Plugin -->
<plugin>
<groupId>com.samaxes.maven</groupId>
<artifactId>minify-maven-plugin</artifactId>
<version>1.7.5</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<charset>UTF-8</charset>
<webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
<webappTargetDir>${project.build.directory}/classes</webappTargetDir>
<cssSourceDir>/</cssSourceDir>
<cssTargetDir>/</cssTargetDir>
<cssFinalFile>totp.css</cssFinalFile>
<cssSourceFiles>
<cssSourceFile>license.txt</cssSourceFile>
</cssSourceFiles>
<cssSourceIncludes>
<cssSourceInclude>**/*.css</cssSourceInclude>
</cssSourceIncludes>
<jsSourceDir>/</jsSourceDir>
<jsTargetDir>/</jsTargetDir>
<jsFinalFile>totp.js</jsFinalFile>
<jsSourceFiles>
<jsSourceFile>license.txt</jsSourceFile>
</jsSourceFiles>
<jsSourceIncludes>
<jsSourceInclude>**/*.js</jsSourceInclude>
</jsSourceIncludes>
<!-- Do not minify and include tests -->
<jsSourceExcludes>
<jsSourceExclude>**/*.test.js</jsSourceExclude>
</jsSourceExcludes>
<jsEngine>CLOSURE</jsEngine>
<!-- Disable warnings for JSDoc annotations -->
<closureWarningLevels>
<misplacedTypeAnnotation>OFF</misplacedTypeAnnotation>
<nonStandardJsDocs>OFF</nonStandardJsDocs>
</closureWarningLevels>
</configuration>
<goals>
<goal>minify</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Assembly plugin - for easy distribution -->
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<finalName>${project.artifactId}-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptors>
<descriptor>src/main/assembly/dist.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>make-dist-archive</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<!-- Copy dependencies prior to packaging -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>unpack-dependencies</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<configuration>
<includeScope>runtime</includeScope>
<outputDirectory>${project.build.directory}/classes</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<!-- Verify format using Apache RAT -->
<plugin>
<groupId>org.apache.rat</groupId>
<artifactId>apache-rat-plugin</artifactId>
<version>0.12</version>
<configuration>
<excludes>
<exclude>**/*.json</exclude>
<exclude>src/licenses/**/*</exclude>
<exclude>src/main/resources/templates/*.html</exclude>
</excludes>
</configuration>
<!-- Bind RAT to validate phase -->
<executions>
<execution>
<id>validate</id>
<phase>validate</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Guacamole Extension API -->
<dependency>
<groupId>org.apache.guacamole</groupId>
<artifactId>guacamole-ext</artifactId>
<version>0.9.14</version>
<scope>provided</scope>
</dependency>
<!-- Guice -->
<dependency>
<groupId>com.google.inject</groupId>
<artifactId>guice</artifactId>
<version>3.0</version>
</dependency>
<dependency>
<groupId>com.google.inject.extensions</groupId>
<artifactId>guice-multibindings</artifactId>
<version>3.0</version>
</dependency>
<!-- Java servlet API -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<!-- Guava - Utility Library -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>18.0</version>
</dependency>
<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<!-- ZXing - Barcode library -->
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>javase</artifactId>
<version>3.3.1</version>
</dependency>
<dependency>
<groupId>com.google.zxing</groupId>
<artifactId>core</artifactId>
<version>3.3.1</version>
</dependency>
<!-- Guacamole depends on an implementation of JAX-WS -->
<dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,294 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
==============================================================================
APACHE GUACAMOLE SUBCOMPONENTS
Apache Guacamole includes a number of subcomponents with separate copyright
notices and license terms. Your use of these subcomponents is subject to the
terms and conditions of the following licenses.
AOP Alliance (http://aopalliance.sourceforge.net/)
--------------------------------------------------
Version: 1.0
From: 'AOP Alliance' (http://aopalliance.sourceforge.net/members.html)
License(s):
Public Domain (bundled/aopalliance-1.0/LICENSE)
Google Guice (https://github.com/google/guice)
----------------------------------------------
Version: 3.0
From: 'Google Inc.' (http://www.google.com/)
License(s):
Apache v2.0 (bundled/guice-3.0/COPYING)
Guava: Google Core Libraries for Java (https://github.com/google/guava)
-----------------------------------------------------------------------
Version: 18.0
From: 'Google Inc.' (http://www.google.com/)
License(s):
Apache v2.0 (bundled/guava-18.0/COPYING)
JSR-330 / Dependency Injection for Java (http://code.google.com/p/atinject/)
----------------------------------------------------------------------------
Version: 1
From: 'JSR-330 Expert Group' (https://jcp.org/en/jsr/detail?id=330)
License(s):
Apache v2.0 (bundled/javax.inject-1/LICENSE-2.0.txt)
TOTP Reference Implementation (https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl)
-------------------------------------------------------------------------------
Verson: 07
From: 'IETF Trust' (http://trustee.ietf.org/license-info)
License(s):
BSD 3-clause (bundled/totp-reference-impl-07/license.txt)
Copyright (c) 2011 IETF Trust and the persons identified as authors
of the code. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Internet Society, IETF or IETF Trust, nor the names
of specific contributors, may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
ZXing Barcode Scanning Library (https://github.com/zxing/zxing/)
----------------------------------------------------------------
Version: 3.3.1
From: 'ZXing authors' (https://github.com/zxing/zxing/blob/zxing-3.3.1/AUTHORS)
License(s):
Apache v2.0 (bundled/zxing-3.3.1/LICENSE)

View File

@@ -0,0 +1,5 @@
Apache Guacamole
Copyright 2017 The Apache Software Foundation
This product includes software developed at
The Apache Software Foundation (http://www.apache.org/).

View File

@@ -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.

View File

@@ -0,0 +1,4 @@
From http://aopalliance.sourceforge.net/:
LICENCE: all the source code provided by AOP Alliance is Public Domain.

View File

@@ -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.

View File

@@ -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.

View File

@@ -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.

View File

@@ -0,0 +1,28 @@
Copyright (c) 2011 IETF Trust and the persons identified as authors
of the code. All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
- Neither the name of Internet Society, IETF or IETF Trust, nor the names
of specific contributors, may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@@ -0,0 +1,245 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
========================================================================
jai-imageio
========================================================================
Copyright (c) 2005 Sun Microsystems, Inc.
Copyright © 2010-2014 University of Manchester
Copyright © 2010-2015 Stian Soiland-Reyes
Copyright © 2015 Peter Hull
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
- Redistribution of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
- Redistribution in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in
the documentation and/or other materials provided with the
distribution.
Neither the name of Sun Microsystems, Inc. or the names of
contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
This software is provided "AS IS," without a warranty of any
kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
You acknowledge that this software is not designed or intended for
use in the design, construction, operation or maintenance of any
nuclear facility.

View File

@@ -0,0 +1,53 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>dist</id>
<baseDirectory>${project.artifactId}-${project.version}</baseDirectory>
<!-- Output tar.gz -->
<formats>
<format>tar.gz</format>
</formats>
<!-- Include licenses and extension .jar -->
<fileSets>
<!-- Include licenses -->
<fileSet>
<outputDirectory></outputDirectory>
<directory>src/licenses</directory>
</fileSet>
<!-- Include extension .jar -->
<fileSet>
<directory>target</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>

View File

@@ -0,0 +1,126 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp;
import org.apache.guacamole.auth.totp.user.UserVerificationService;
import com.google.inject.Guice;
import com.google.inject.Injector;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.totp.user.CodeUsageTrackingService;
import org.apache.guacamole.auth.totp.user.TOTPUserContext;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.AuthenticationProvider;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.UserContext;
/**
* AuthenticationProvider implementation which uses TOTP as an additional
* authentication factor for users which have already been authenticated by
* some other AuthenticationProvider.
*/
public class TOTPAuthenticationProvider implements AuthenticationProvider {
/**
* Injector which will manage the object graph of this authentication
* provider.
*/
private final Injector injector;
/**
* Creates a new TOTPAuthenticationProvider that verifies users using TOTP.
*
* @throws GuacamoleException
* If a required property is missing, or an error occurs while parsing
* a property.
*/
public TOTPAuthenticationProvider() throws GuacamoleException {
// Set up Guice injector.
injector = Guice.createInjector(
new TOTPAuthenticationProviderModule(this)
);
}
@Override
public String getIdentifier() {
return "totp";
}
@Override
public Object getResource() {
return null;
}
@Override
public AuthenticatedUser authenticateUser(Credentials credentials)
throws GuacamoleException {
return null;
}
@Override
public AuthenticatedUser updateAuthenticatedUser(AuthenticatedUser authenticatedUser,
Credentials credentials) throws GuacamoleException {
return authenticatedUser;
}
@Override
public UserContext getUserContext(AuthenticatedUser authenticatedUser)
throws GuacamoleException {
return null;
}
@Override
public UserContext updateUserContext(UserContext context,
AuthenticatedUser authenticatedUser, Credentials credentials)
throws GuacamoleException {
return context;
}
@Override
public UserContext decorate(UserContext context,
AuthenticatedUser authenticatedUser, Credentials credentials)
throws GuacamoleException {
UserVerificationService verificationService =
injector.getInstance(UserVerificationService.class);
// Verify identity of user
verificationService.verifyIdentity(context, authenticatedUser);
// User has been verified, and authentication should be allowed to
// continue
return new TOTPUserContext(context);
}
@Override
public UserContext redecorate(UserContext decorated, UserContext context,
AuthenticatedUser authenticatedUser, Credentials credentials)
throws GuacamoleException {
return new TOTPUserContext(context);
}
@Override
public void shutdown() {
injector.getInstance(CodeUsageTrackingService.class).shutdown();
}
}

View File

@@ -0,0 +1,83 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp;
import org.apache.guacamole.auth.totp.user.UserVerificationService;
import com.google.inject.AbstractModule;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
import org.apache.guacamole.auth.totp.user.CodeUsageTrackingService;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.environment.LocalEnvironment;
import org.apache.guacamole.net.auth.AuthenticationProvider;
/**
* Guice module which configures TOTP-specific injections.
*/
public class TOTPAuthenticationProviderModule extends AbstractModule {
/**
* Guacamole server environment.
*/
private final Environment environment;
/**
* A reference to the TOTPAuthenticationProvider on behalf of which this
* module has configured injection.
*/
private final AuthenticationProvider authProvider;
/**
* Creates a new TOTP authentication provider module which configures
* injection for the TOTPAuthenticationProvider.
*
* @param authProvider
* The AuthenticationProvider for which injection is being configured.
*
* @throws GuacamoleException
* If an error occurs while retrieving the Guacamole server
* environment.
*/
public TOTPAuthenticationProviderModule(AuthenticationProvider authProvider)
throws GuacamoleException {
// Get local environment
this.environment = new LocalEnvironment();
// Store associated auth provider
this.authProvider = authProvider;
}
@Override
protected void configure() {
// Bind core implementations of guacamole-ext classes
bind(AuthenticationProvider.class).toInstance(authProvider);
bind(Environment.class).toInstance(environment);
// Bind TOTP-specific services
bind(CodeUsageTrackingService.class);
bind(ConfigurationService.class);
bind(UserVerificationService.class);
}
}

View File

@@ -0,0 +1,161 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.conf;
import com.google.inject.Inject;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.environment.Environment;
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
import org.apache.guacamole.properties.StringGuacamoleProperty;
import org.apache.guacamole.totp.TOTPGenerator;
/**
* Service for retrieving configuration information regarding the TOTP
* authentication extension.
*/
public class ConfigurationService {
/**
* The Guacamole server environment.
*/
@Inject
private Environment environment;
/**
* The human-readable name of the entity issuing user accounts. By default,
* this will be "Apache Guacamole".
*/
private static final StringGuacamoleProperty TOTP_ISSUER =
new StringGuacamoleProperty() {
@Override
public String getName() { return "totp-issuer"; }
};
/**
* The number of digits which should be included in each generated TOTP
* code. By default, this will be 6.
*/
private static final IntegerGuacamoleProperty TOTP_DIGITS=
new IntegerGuacamoleProperty() {
@Override
public String getName() { return "totp-digits"; }
};
/**
* The duration that each generated code should remain valid, in seconds.
* By default, this will be 30.
*/
private static final IntegerGuacamoleProperty TOTP_PERIOD =
new IntegerGuacamoleProperty() {
@Override
public String getName() { return "totp-period"; }
};
/**
* The hash algorithm that should be used to generate TOTP codes. By
* default, this will be "sha1". Legal values are "sha1", "sha256", and
* "sha512".
*/
private static final TOTPModeProperty TOTP_MODE =
new TOTPModeProperty() {
@Override
public String getName() { return "totp-mode"; }
};
/**
* Returns the human-readable name of the entity issuing user accounts. If
* not specified, "Apache Guacamole" will be used by default.
*
* @return
* The human-readable name of the entity issuing user accounts.
*
* @throws GuacamoleException
* If the "totp-issuer" property cannot be read from
* guacamole.properties.
*/
public String getIssuer() throws GuacamoleException {
return environment.getProperty(TOTP_ISSUER, "Apache Guacamole");
}
/**
* Returns the number of digits which should be included in each generated
* TOTP code. If not specified, 6 will be used by default.
*
* @return
* The number of digits which should be included in each generated
* TOTP code.
*
* @throws GuacamoleException
* If the "totp-digits" property cannot be read from
* guacamole.properties.
*/
public int getDigits() throws GuacamoleException {
// Validate legal number of digits
int digits = environment.getProperty(TOTP_DIGITS, 6);
if (digits < 6 || digits > 8)
throw new GuacamoleServerException("TOTP codes may have no fewer "
+ "than 6 digits and no more than 8 digits.");
return digits;
}
/**
* Returns the duration that each generated code should remain valid, in
* seconds. If not specified, 30 will be used by default.
*
* @return
* The duration that each generated code should remain valid, in
* seconds.
*
* @throws GuacamoleException
* If the "totp-period" property cannot be read from
* guacamole.properties.
*/
public int getPeriod() throws GuacamoleException {
return environment.getProperty(TOTP_PERIOD, 30);
}
/**
* Returns the hash algorithm that should be used to generate TOTP codes. If
* not specified, SHA1 will be used by default.
*
* @return
* The hash algorithm that should be used to generate TOTP codes.
*
* @throws GuacamoleException
* If the "totp-mode" property cannot be read from
* guacamole.properties.
*/
public TOTPGenerator.Mode getMode() throws GuacamoleException {
return environment.getProperty(TOTP_MODE, TOTPGenerator.Mode.SHA1);
}
}

View File

@@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.conf;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleServerException;
import org.apache.guacamole.properties.GuacamoleProperty;
import org.apache.guacamole.totp.TOTPGenerator;
/**
* A GuacamoleProperty whose value is a TOTP generation method. The string
* values "sha1", "sha256", and "sha512" are each parsed to their corresponding
* values within the TOTPGenerator.Mode enum. All other string values result in
* parse errors.
*/
public abstract class TOTPModeProperty
implements GuacamoleProperty<TOTPGenerator.Mode> {
@Override
public TOTPGenerator.Mode parseValue(String value)
throws GuacamoleException {
// If no value provided, return null.
if (value == null)
return null;
// SHA1
if (value.equals("sha1"))
return TOTPGenerator.Mode.SHA1;
// SHA256
if (value.equals("sha256"))
return TOTPGenerator.Mode.SHA256;
// SHA512
if (value.equals("sha512"))
return TOTPGenerator.Mode.SHA512;
// The provided value is not legal
throw new GuacamoleServerException("TOTP mode must be one of "
+ "\"sha1\", \"sha256\", or \"sha512\".");
}
}

View File

@@ -0,0 +1,316 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.form;
import com.google.common.io.BaseEncoding;
import com.google.inject.Inject;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.WriterException;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import com.google.zxing.qrcode.QRCodeWriter;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.net.URI;
import javax.ws.rs.core.UriBuilder;
import javax.xml.bind.DatatypeConverter;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.totp.user.UserTOTPKey;
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
import org.apache.guacamole.form.Field;
import org.apache.guacamole.totp.TOTPGenerator;
import org.codehaus.jackson.annotate.JsonProperty;
/**
* Field which prompts the user for an authentication code generated via TOTP.
*/
public class AuthenticationCodeField extends Field {
/**
* The name of the HTTP parameter which will contain the TOTP code provided
* by the user to verify their identity.
*/
public static final String PARAMETER_NAME = "guac-totp";
/**
* The unique name associated with this field type.
*/
private static final String FIELD_TYPE_NAME = "GUAC_TOTP_CODE";
/**
* The width of QR codes to generate, in pixels.
*/
private static final int QR_CODE_WIDTH = 256;
/**
* The height of QR codes to generate, in pixels.
*/
private static final int QR_CODE_HEIGHT = 256;
/**
* BaseEncoding which encodes/decodes base32.
*/
private static final BaseEncoding BASE32 = BaseEncoding.base32();
/**
* Service for retrieving configuration information.
*/
@Inject
private ConfigurationService confService;
/**
* The TOTP key to expose to the user for the sake of enrollment, if any.
* If no such key should be exposed to the user, this will be null.
*/
private UserTOTPKey key;
/**
* Creates a new field which prompts the user for an authentication code
* generated via TOTP. The user's TOTP key is not exposed for enrollment.
*/
public AuthenticationCodeField() {
super(PARAMETER_NAME, FIELD_TYPE_NAME);
}
/**
* Exposes the given key to facilitate enrollment.
*
* @param key
* The TOTP key to expose to the user for the sake of enrollment.
*/
public void exposeKey(UserTOTPKey key) {
this.key = key;
}
/**
* Returns the username of the user associated with the key being used to
* generate TOTP codes. If the user's key is not being exposed to facilitate
* enrollment, this value will not be exposed either.
*
* @return
* The username of the user associated with the key being used to
* generate TOTP codes, or null if the user's key is not being exposed
* to facilitate enrollment.
*/
public String getUsername() {
// Do not reveal TOTP mode unless enrollment is in progress
if (key == null)
return null;
return key.getUsername();
}
/**
* Returns the base32-encoded secret key that is being used to generate TOTP
* codes for the authenticating user. If the user's key is not being exposed
* to facilitate enrollment, this value will not be exposed either.
*
* @return
* The base32-encoded secret key that is being used to generate TOTP
* codes for the authenticating user, or null if the user's key is not
* being exposed to facilitate enrollment.
*/
public String getSecret() {
// Do not reveal TOTP mode unless enrollment is in progress
if (key == null)
return null;
return BASE32.encode(key.getSecret());
}
/**
* Returns the number of digits used for each TOTP code. If the user's key
* is not being exposed to facilitate enrollment, this value will not be
* exposed either.
*
* @return
* The number of digits used for each TOTP code, or null if the user's
* key is not being exposed to facilitate enrollment.
*
* @throws GuacamoleException
* If the number of digits cannot be read from guacamole.properties.
*/
public Integer getDigits() throws GuacamoleException {
// Do not reveal code size unless enrollment is in progress
if (key == null)
return null;
return confService.getDigits();
}
/**
* Returns the human-readable name of the entity issuing user accounts. If
* the user's key is not being exposed to facilitate enrollment, this value
* will not be exposed either.
*
* @return
* The human-readable name of the entity issuing user accounts, or null
* if the user's key is not being exposed to facilitate enrollment.
*
* @throws GuacamoleException
* If the issuer cannot be read from guacamole.properties.
*/
public String getIssuer() throws GuacamoleException {
// Do not reveal code issuer unless enrollment is in progress
if (key == null)
return null;
return confService.getIssuer();
}
/**
* Returns the mode that TOTP code generation is operating in. This value
* will be one of "SHA1", "SHA256", or "SHA512". If the user's key is not
* being exposed to facilitate enrollment, this value will not be exposed
* either.
*
* @return
* The mode that TOTP code generation is operating in, such as "SHA1",
* "SHA256", or "SHA512", or null if the user's key is not being
* exposed to facilitate enrollment.
*
* @throws GuacamoleException
* If the TOTP mode cannot be read from guacamole.properties.
*/
public TOTPGenerator.Mode getMode() throws GuacamoleException {
// Do not reveal TOTP mode unless enrollment is in progress
if (key == null)
return null;
return confService.getMode();
}
/**
* Returns the number of seconds that each TOTP code remains valid. If the
* user's key is not being exposed to facilitate enrollment, this value will
* not be exposed either.
*
* @return
* The number of seconds that each TOTP code remains valid, or null if
* the user's key is not being exposed to facilitate enrollment.
*
* @throws GuacamoleException
* If the period cannot be read from guacamole.properties.
*/
public Integer getPeriod() throws GuacamoleException {
// Do not reveal code period unless enrollment is in progress
if (key == null)
return null;
return confService.getPeriod();
}
/**
* Returns the "otpauth" URI for the secret key used to generate TOTP codes
* for the current user. If the secret key is not being exposed to
* facilitate enrollment, null is returned.
*
* @return
* The "otpauth" URI for the secret key used to generate TOTP codes
* for the current user, or null is the secret ket is not being exposed
* to facilitate enrollment.
*
* @throws GuacamoleException
* If the configuration information required for generating the key URI
* cannot be read from guacamole.properties.
*/
@JsonProperty("keyUri")
public URI getKeyURI() throws GuacamoleException {
// Do not generate a key URI if no key is being exposed
if (key == null)
return null;
// Format "otpauth" URL (see https://github.com/google/google-authenticator/wiki/Key-Uri-Format)
String issuer = confService.getIssuer();
return UriBuilder.fromUri("otpauth://totp/")
.path(issuer + ":" + key.getUsername())
.queryParam("secret", BASE32.encode(key.getSecret()))
.queryParam("issuer", issuer)
.queryParam("algorithm", confService.getMode())
.queryParam("digits", confService.getDigits())
.queryParam("period", confService.getPeriod())
.build();
}
/**
* Returns the URL of a QR code describing the user's TOTP key and
* configuration. If the key is not being exposed for enrollment, null is
* returned.
*
* @return
* The URL of a QR code describing the user's TOTP key and
* configuration, or null if the key is not being exposed for
* enrollment.
*
* @throws GuacamoleException
* If the configuration information required for generating the QR code
* cannot be read from guacamole.properties.
*/
@JsonProperty("qrCode")
public String getQRCode() throws GuacamoleException {
// Do not generate a QR code if no key is being exposed
URI keyURI = getKeyURI();
if (keyURI == null)
return null;
ByteArrayOutputStream stream = new ByteArrayOutputStream();
try {
// Create QR code writer
QRCodeWriter writer = new QRCodeWriter();
BitMatrix matrix = writer.encode(keyURI.toString(),
BarcodeFormat.QR_CODE, QR_CODE_WIDTH, QR_CODE_HEIGHT);
// Produce PNG image of TOTP key text
MatrixToImageWriter.writeToStream(matrix, "PNG", stream);
}
catch (WriterException e) {
throw new IllegalArgumentException("QR code could not be "
+ "generated for TOTP key.", e);
}
catch (IOException e) {
throw new IllegalStateException("Image stream of QR code could "
+ "not be written.", e);
}
// Return data URI for generated image
return "data:image/png;base64,"
+ DatatypeConverter.printBase64Binary(stream.toByteArray());
}
}

View File

@@ -0,0 +1,264 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.user;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Service for tracking past valid uses of TOTP codes. An internal thread
* periodically walks through records of past codes, removing records which
* should be invalid by their own nature (no longer matching codes generated by
* the secret key).
*/
@Singleton
public class CodeUsageTrackingService {
/**
* The number of periods during which a previously-used code should remain
* unusable. Once this period has elapsed, the code can be reused again if
* it is otherwise valid.
*/
private static final int INVALID_INTERVAL = 2;
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(CodeUsageTrackingService.class);
/**
* Executor service which runs the cleanup task.
*/
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
/**
* Service for retrieving configuration information.
*/
@Inject
private ConfigurationService confService;
/**
* Map of previously-used codes to the timestamp after which the code can
* be used again, providing the TOTP key legitimately generates that code.
*/
private final ConcurrentMap<UsedCode, Long> invalidCodes =
new ConcurrentHashMap<UsedCode, Long>();
/**
* Creates a new CodeUsageTrackingService which tracks past valid uses of
* TOTP codes on a per-user basis.
*/
public CodeUsageTrackingService() {
executor.scheduleAtFixedRate(new CodeEvictionTask(), 1, 1, TimeUnit.MINUTES);
}
/**
* Task which iterates through all explicitly-invalidated codes, evicting
* those codes which are old enough that they would fail validation against
* the secret key anyway.
*/
private class CodeEvictionTask implements Runnable {
@Override
public void run() {
// Get start time of cleanup check
long checkStart = System.currentTimeMillis();
// For each code still being tracked, remove those which are old
// enough that they would fail validation against the secret key
Iterator<Map.Entry<UsedCode, Long>> entries = invalidCodes.entrySet().iterator();
while (entries.hasNext()) {
Map.Entry<UsedCode, Long> entry = entries.next();
long invalidUntil = entry.getValue();
// If code is sufficiently old, evict it and check the next one
if (checkStart >= invalidUntil)
entries.remove();
}
// Log completion and duration
logger.debug("TOTP tracking cleanup check completed in {} ms.",
System.currentTimeMillis() - checkStart);
}
}
/**
* A valid TOTP code which was previously used by a particular user.
*/
private class UsedCode {
/**
* The username of the user which previously used this code.
*/
private final String username;
/**
* The valid code given by the user.
*/
private final String code;
/**
* Creates a new UsedCode which records the given code as having been
* used by the given user.
*
* @param username
* The username of the user which previously used the given code.
*
* @param code
* The valid code given by the user.
*/
public UsedCode(String username, String code) {
this.username = username;
this.code = code;
}
/**
* Returns the username of the user which previously used the code
* associated with this UsedCode.
*
* @return
* The username of the user which previously used this code.
*/
public String getUsername() {
return username;
}
/**
* Returns the valid code given by the user when this UsedCode was
* created.
*
* @return
* The valid code given by the user.
*/
public String getCode() {
return code;
}
@Override
public int hashCode() {
int hash = 7;
hash = 79 * hash + this.username.hashCode();
hash = 79 * hash + this.code.hashCode();
return hash;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
final UsedCode other = (UsedCode) obj;
return username.equals(other.username) && code.equals(other.code);
}
}
/**
* Attempts to mark the given code as used. The code MUST have already been
* validated against the user's secret key, as this function only verifies
* whether the code has been previously used, not whether it is actually
* valid. If the code has not previously been used, the code is stored as
* having been used by the given user at the current time.
*
* @param username
* The username of the user who has attempted to use the given valid
* code.
*
* @param code
* The otherwise-valid code given by the user.
*
* @return
* true if the code has not previously been used by the given user and
* has now been marked as previously used, false otherwise.
*
* @throws GuacamoleException
* If configuration information necessary to determine the length of
* time a code should be marked as invalid cannot be read from
* guacamole.properties.
*/
public boolean useCode(String username, String code)
throws GuacamoleException {
// Repeatedly attempt to use the given code until an explicit success
// or failure has occurred
UsedCode usedCode = new UsedCode(username, code);
for (;;) {
// Explicitly invalidate each used code for two periods after its
// first successful use
long current = System.currentTimeMillis();
long invalidUntil = current + confService.getPeriod() * 1000 * INVALID_INTERVAL;
// Try to use the given code, marking it as used within the map of
// now-invalidated codes
Long expires = invalidCodes.putIfAbsent(usedCode, invalidUntil);
if (expires == null)
return true;
// If the code was already used, fail to use the code if
// insufficient time has elapsed since it was last used
// successfully
if (expires > current)
return false;
// Otherwise, the code is actually valid - remove the invalidated
// code only if it still has the expected expiration time, and
// retry using the code
invalidCodes.remove(usedCode, expires);
}
}
/**
* Cleans up resources which may be in use by this service in the
* background, such as other threads. This function MUST be invoked during
* webapp shutdown to avoid leaking these resources.
*/
public void shutdown() {
executor.shutdownNow();
}
}

View File

@@ -0,0 +1,102 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.user;
import java.util.HashMap;
import java.util.Map;
import org.apache.guacamole.net.auth.DelegatingUser;
import org.apache.guacamole.net.auth.User;
/**
* TOTP-specific User implementation which wraps a User from another extension,
* hiding and blocking access to the core attributes used by TOTP.
*/
public class TOTPUser extends DelegatingUser {
/**
* The name of the user attribute which stores the TOTP key.
*/
public static final String TOTP_KEY_SECRET_ATTRIBUTE_NAME = "guac-totp-key-secret";
/**
* The name of the user attribute defines whether the TOTP key has been
* confirmed by the user, and the user is thus fully enrolled.
*/
public static final String TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME = "guac-totp-key-confirmed";
/**
* The User object wrapped by this TOTPUser.
*/
private final User undecorated;
/**
* Wraps the given User object, hiding and blocking access to the core
* attributes used by TOTP.
*
* @param user
* The User object to wrap.
*/
public TOTPUser(User user) {
super(user);
this.undecorated = user;
}
/**
* Returns the User object wrapped by this TOTPUser.
*
* @return
* The wrapped User object.
*/
public User getUndecorated() {
return undecorated;
}
@Override
public Map<String, String> getAttributes() {
// Create independent, mutable copy of attributes
Map<String, String> attributes =
new HashMap<String, String>(super.getAttributes());
// Do not expose any TOTP-related attributes outside this extension
attributes.remove(TOTP_KEY_SECRET_ATTRIBUTE_NAME);
attributes.remove(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME);
// Expose only non-TOTP attributes
return attributes;
}
@Override
public void setAttributes(Map<String, String> attributes) {
// Create independent, mutable copy of attributes
attributes = new HashMap<String, String>(attributes);
// Do not expose any TOTP-related attributes outside this extension
attributes.remove(TOTP_KEY_SECRET_ATTRIBUTE_NAME);
attributes.remove(TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME);
// Set only non-TOTP attributes
super.setAttributes(attributes);
}
}

View File

@@ -0,0 +1,64 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.user;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.net.auth.DecoratingDirectory;
import org.apache.guacamole.net.auth.DelegatingUserContext;
import org.apache.guacamole.net.auth.Directory;
import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext;
/**
* TOTP-specific UserContext implementation which wraps the UserContext of
* some other extension, providing (or hiding) additional data.
*/
public class TOTPUserContext extends DelegatingUserContext {
/**
* Creates a new TOTPUserContext which wraps the given UserContext,
* providing (or hiding) additional TOTP-specific data.
*
* @param userContext
* The UserContext to wrap.
*/
public TOTPUserContext(UserContext userContext) {
super(userContext);
}
@Override
public Directory<User> getUserDirectory() throws GuacamoleException {
return new DecoratingDirectory<User>(super.getUserDirectory()) {
@Override
protected User decorate(User object) {
return new TOTPUser(object);
}
@Override
protected User undecorate(User object) {
assert(object instanceof TOTPUser);
return ((TOTPUser) object).getUndecorated();
}
};
}
}

View File

@@ -0,0 +1,148 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.user;
import java.security.SecureRandom;
import java.util.Random;
/**
* The key used to generate TOTP codes for a particular user.
*/
public class UserTOTPKey {
/**
* Secure source of random bytes.
*/
private static final Random RANDOM = new SecureRandom();
/**
* The username of the user associated with this key.
*/
private final String username;
/**
* Whether the associated secret key has been confirmed by the user. A key
* is confirmed once the user has successfully entered a valid TOTP
* derived from that key.
*/
private boolean confirmed;
/**
* The base32-encoded TOTP key associated with the user.
*/
private byte[] secret;
/**
* Generates the given number of random bytes.
*
* @param length
* The number of random bytes to generate.
*
* @return
* A new array of exactly the given number of random bytes.
*/
private static byte[] generateBytes(int length) {
byte[] bytes = new byte[length];
RANDOM.nextBytes(bytes);
return bytes;
}
/**
* Creates a new, unconfirmed, randomly-generated TOTP key having the given
* length.
*
* @param username
* The username of the user associated with this key.
*
* @param length
* The length of the key to generate, in bytes.
*/
public UserTOTPKey(String username, int length) {
this(username, generateBytes(length), false);
}
/**
* Creates a new UserTOTPKey containing the given key and having the given
* confirmed state.
*
* @param username
* The username of the user associated with this key.
*
* @param secret
* The raw binary secret key to be used to generate TOTP codes.
*
* @param confirmed
* true if the user associated with the key has confirmed that they can
* successfully generate the corresponding TOTP codes (the user has
* been "enrolled"), false otherwise.
*/
public UserTOTPKey(String username, byte[] secret, boolean confirmed) {
this.username = username;
this.confirmed = confirmed;
this.secret = secret;
}
/**
* Returns the username of the user associated with this key.
*
* @return
* The username of the user associated with this key.
*/
public String getUsername() {
return username;
}
/**
* Returns the raw binary secret key to be used to generate TOTP codes.
*
* @return
* The raw binary secret key to be used to generate TOTP codes.
*/
public byte[] getSecret() {
return secret;
}
/**
* Returns whether the user associated with the key has confirmed that they
* can successfully generate the corresponding TOTP codes (the user has
* been "enrolled").
*
* @return
* true if the user has confirmed that they can successfully generate
* the TOTP codes generated by this key, false otherwise.
*/
public boolean isConfirmed() {
return confirmed;
}
/**
* Sets whether the user associated with the key has confirmed that they
* can successfully generate the corresponding TOTP codes (the user has
* been "enrolled").
*
* @param confirmed
* true if the user has confirmed that they can successfully generate
* the TOTP codes generated by this key, false otherwise.
*/
public void setConfirmed(boolean confirmed) {
this.confirmed = confirmed;
}
}

View File

@@ -0,0 +1,288 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.auth.totp.user;
import com.google.common.io.BaseEncoding;
import com.google.inject.Inject;
import com.google.inject.Provider;
import java.security.InvalidKeyException;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.http.HttpServletRequest;
import org.apache.guacamole.GuacamoleClientException;
import org.apache.guacamole.GuacamoleException;
import org.apache.guacamole.GuacamoleUnsupportedException;
import org.apache.guacamole.auth.totp.conf.ConfigurationService;
import org.apache.guacamole.auth.totp.form.AuthenticationCodeField;
import org.apache.guacamole.form.Field;
import org.apache.guacamole.net.auth.AuthenticatedUser;
import org.apache.guacamole.net.auth.Credentials;
import org.apache.guacamole.net.auth.User;
import org.apache.guacamole.net.auth.UserContext;
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
import org.apache.guacamole.net.auth.credentials.GuacamoleInsufficientCredentialsException;
import org.apache.guacamole.totp.TOTPGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Service for verifying the identity of a user using TOTP.
*/
public class UserVerificationService {
/**
* Logger for this class.
*/
private final Logger logger = LoggerFactory.getLogger(UserVerificationService.class);
/**
* BaseEncoding instance which decoded/encodes base32.
*/
private static final BaseEncoding BASE32 = BaseEncoding.base32();
/**
* Service for retrieving configuration information.
*/
@Inject
private ConfigurationService confService;
/**
* Service for tracking whether TOTP codes have been used.
*/
@Inject
private CodeUsageTrackingService codeService;
/**
* Provider for AuthenticationCodeField instances.
*/
@Inject
private Provider<AuthenticationCodeField> codeFieldProvider;
/**
* Retrieves and decodes the base32-encoded TOTP key associated with user
* having the given UserContext. If no TOTP key is associated with the user,
* a random key is generated and associated with the user. If the extension
* storing the user does not support storage of the TOTP key, null is
* returned.
*
* @param context
* The UserContext of the user whose TOTP key should be retrieved.
*
* @param username
* The username of the user associated with the given UserContext.
*
* @return
* The TOTP key associated with the user having the given UserContext,
* or null if the extension storing the user does not support storage
* of the TOTP key.
*
* @throws GuacamoleException
* If a new key is generated, but the extension storing the associated
* user fails while updating the user account.
*/
private UserTOTPKey getKey(UserContext context,
String username) throws GuacamoleException {
// Retrieve attributes from current user
User self = context.self();
Map<String, String> attributes = context.self().getAttributes();
// If no key is defined, attempt to generate a new key
String secret = attributes.get(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME);
if (secret == null) {
// Generate random key for user
TOTPGenerator.Mode mode = confService.getMode();
UserTOTPKey generated = new UserTOTPKey(username,mode.getRecommendedKeyLength());
if (setKey(context, generated))
return generated;
// Fail if key cannot be set
return null;
}
// Parse retrieved base32 key value
byte[] key;
try {
key = BASE32.decode(secret);
}
// If key is not valid base32, warn but otherwise pretend the key does
// not exist
catch (IllegalArgumentException e) {
logger.warn("TOTP key of user \"{}\" is not valid base32.", self.getIdentifier());
logger.debug("TOTP key is not valid base32.", e);
return null;
}
// Otherwise, parse value from attributes
boolean confirmed = "true".equals(attributes.get(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME));
return new UserTOTPKey(username, key, confirmed);
}
/**
* Attempts to store the given TOTP key within the user account of the user
* having the given UserContext. As not all extensions will support storage
* of arbitrary attributes, this operation may fail.
*
* @param context
* The UserContext associated with the user whose TOTP key is to be
* stored.
*
* @param key
* The TOTP key to store.
*
* @return
* true if the TOTP key was successfully stored, false if the extension
* handling storage does not support storage of the key.
*
* @throws GuacamoleException
* If the extension handling storage fails internally while attempting
* to update the user.
*/
private boolean setKey(UserContext context, UserTOTPKey key)
throws GuacamoleException {
// Get mutable set of attributes
User self = context.self();
Map<String, String> attributes = new HashMap<String, String>();
// Set/overwrite current TOTP key state
attributes.put(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME, BASE32.encode(key.getSecret()));
attributes.put(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME, key.isConfirmed() ? "true" : "false");
self.setAttributes(attributes);
// Confirm that attributes have actually been set
Map<String, String> setAttributes = self.getAttributes();
if (!setAttributes.containsKey(TOTPUser.TOTP_KEY_SECRET_ATTRIBUTE_NAME)
|| !setAttributes.containsKey(TOTPUser.TOTP_KEY_CONFIRMED_ATTRIBUTE_NAME))
return false;
// Update user object
try {
context.getUserDirectory().update(self);
}
catch (GuacamoleUnsupportedException e) {
logger.debug("Extension storage for user is explicitly read-only. "
+ "Cannot update attributes to store TOTP key.", e);
return false;
}
// TOTP key successfully stored/updated
return true;
}
/**
* Verifies the identity of the given user using TOTP. If a authentication
* code from the user's TOTP device has not already been provided, a code is
* requested in the form of additional expected credentials. Any provided
* code is cryptographically verified. If no code is present, or the
* received code is invalid, an exception is thrown.
*
* @param context
* The UserContext provided for the user by another authentication
* extension.
*
* @param authenticatedUser
* The user whose identity should be verified using TOTP.
*
* @throws GuacamoleException
* If required TOTP-specific configuration options are missing or
* malformed, or if the user's identity cannot be verified.
*/
public void verifyIdentity(UserContext context,
AuthenticatedUser authenticatedUser) throws GuacamoleException {
// Ignore anonymous users
String username = authenticatedUser.getIdentifier();
if (username.equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER))
return;
// Ignore users which do not have an associated key
UserTOTPKey key = getKey(context, username);
if (key == null)
return;
// Pull the original HTTP request used to authenticate
Credentials credentials = authenticatedUser.getCredentials();
HttpServletRequest request = credentials.getRequest();
// Retrieve TOTP from request
String code = request.getParameter(AuthenticationCodeField.PARAMETER_NAME);
// If no TOTP provided, request one
if (code == null) {
AuthenticationCodeField field = codeFieldProvider.get();
// If the user hasn't completed enrollment, request that they do
if (!key.isConfirmed()) {
field.exposeKey(key);
throw new GuacamoleInsufficientCredentialsException(
"TOTP.INFO_ENROLL_REQUIRED", new CredentialsInfo(
Collections.<Field>singletonList(field)
));
}
// Otherwise simply request the user's authentication code
throw new GuacamoleInsufficientCredentialsException(
"TOTP.INFO_CODE_REQUIRED", new CredentialsInfo(
Collections.<Field>singletonList(field)
));
}
try {
// Get generator based on user's key and provided configuration
TOTPGenerator totp = new TOTPGenerator(key.getSecret(),
confService.getMode(), confService.getDigits());
// Verify provided TOTP against value produced by generator
if ((code.equals(totp.generate()) || code.equals(totp.previous()))
&& codeService.useCode(username, code)) {
// Record key as confirmed, if it hasn't already been so recorded
if (!key.isConfirmed()) {
key.setConfirmed(true);
setKey(context, key);
}
// User has been verified
return;
}
}
catch (InvalidKeyException e) {
logger.warn("User \"{}\" is associated with an invalid TOTP key.", username);
logger.debug("TOTP key is not valid.", e);
}
// Provided code is not valid
throw new GuacamoleClientException("TOTP.INFO_VERIFICATION_FAILED");
}
}

View File

@@ -0,0 +1,456 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.totp;
import com.google.common.primitives.Longs;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
/*
* NOTE: This TOTP implementation is based on the TOTP reference implementation
* provided by the IETF Trust at:
*
* https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl
*/
/*
* Copyright (c) 2011 IETF Trust and the persons identified as authors
* of the code. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of Internet Society, IETF or IETF Trust, nor the names
* of specific contributors, may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Generator which uses the TOTP algorithm to generate authentication codes.
*/
public class TOTPGenerator {
/**
* The default time to use as the basis for comparison when transforming
* provided TOTP timestamps into counter values required for HOTP, in
* seconds since midnight, 1970-01-01, UTC (UNIX epoch).
*/
public static final long DEFAULT_START_TIME = 0;
/**
* The default frequency at which new TOTP codes should be generated (and
* old codes invalidated), in seconds.
*/
public static final long DEFAULT_TIME_STEP = 30;
/**
* The TOTP generation mode. The mode dictates the hash function which
* should be used to generate authentication codes, as well as the required
* key size.
*/
private final Mode mode;
/**
* The shared key to use to generate authentication codes. The size
* required for this key depends on the generation mode.
*/
private final Key key;
/**
* The length of codes to generate, in digits.
*/
private final int length;
/**
* The base time against which the timestamp specified for each TOTP
* should be compared to produce the corresponding HOTP counter value, in
* seconds since midnight, 1970-01-01, UTC (UNIX epoch). This is the value
* value referred to as "T0" in the TOTP specification.
*/
private final long startTime;
/**
* The frequency that new TOTP codes should be generated and invalidated,
* in seconds. This is the value referred to as "X" in the TOTP
* specification.
*/
private final long timeStep;
/**
* The operating mode for TOTP, defining the hash algorithm to be used.
*/
public enum Mode {
/**
* TOTP mode which generates hashes using SHA1. TOTP in SHA1 mode
* requires 160-bit keys.
*/
SHA1("HmacSHA1", 20),
/**
* TOTP mode which generates hashes using SHA256. TOTP in SHA256 mode
* requires 256-bit keys.
*/
SHA256("HmacSHA256", 32),
/**
* TOTP mode which generates hashes using SHA512. TOTP in SHA512 mode
* requires 512-bit keys.
*/
SHA512("HmacSHA512", 64);
/**
* The name of the HMAC algorithm which the TOTP implementation should
* use when operating in this mode, in the format required by
* Mac.getInstance().
*/
private final String algorithmName;
/**
* The recommended length of keys generated for TOTP in this mode, in
* bytes. Keys are recommended to be the same length as the hash
* involved.
*/
private final int recommendedKeyLength;
/**
* Creates a new TOTP operating mode which is associated with the
* given HMAC algorithm.
*
* @param algorithmName
* The name of the HMAC algorithm which the TOTP implementation
* should use when operating in this mode, in the format required
* by Mac.getInstance().
*
* @param recommendedKeyLength
* The recommended length of keys generated for TOTP in this mode,
* in bytes.
*/
private Mode(String algorithmName, int recommendedKeyLength) {
this.algorithmName = algorithmName;
this.recommendedKeyLength = recommendedKeyLength;
}
/**
* Returns the name of the HMAC algorithm which the TOTP implementation
* should use when operating in this mode. The name returned will be
* in the format required by Mac.getInstance().
*
* @return
* The name of the HMAC algorithm which the TOTP implementation
* should use.
*/
public String getAlgorithmName() {
return algorithmName;
}
/**
* Returns the recommended length of keys generated for TOTP in this
* mode, in bytes. Keys are recommended to be the same length as the
* hash involved.
*
* @return
* The recommended length of keys generated for TOTP in this mode,
* in bytes.
*/
public int getRecommendedKeyLength() {
return recommendedKeyLength;
}
}
/**
* Creates a new TOTP generator which uses the given shared key to generate
* authentication codes. The provided generation mode dictates the size of
* the key required, while the given start time and time step dictate how
* timestamps provided for code generation are converted to the counter
* value used by HOTP (the algorithm which forms the basis of TOTP).
*
* @param key
* The shared key to use to generate authentication codes.
*
* @param mode
* The mode in which the TOTP algorithm should operate.
*
* @param length
* The length of the codes to generate, in digits. As required
* by the specification, this value MUST be at least 6 but no greater
* than 8.
*
* @param startTime
* The base time against which the timestamp specified for each TOTP
* should be compared to produce the corresponding HOTP counter value,
* in seconds since midnight, 1970-01-01, UTC (UNIX epoch). This is the
* value referred to as "T0" in the TOTP specification.
*
* @param timeStep
* The frequency that new TOTP codes should be generated and
* invalidated, in seconds. This is the value referred to as "X" in the
* TOTP specification.
*
* @throws InvalidKeyException
* If the provided key is invalid for the requested TOTP mode.
*/
public TOTPGenerator(byte[] key, Mode mode, int length, long startTime,
long timeStep) throws InvalidKeyException {
// Validate length is within spec
if (length < 6 || length > 8)
throw new IllegalArgumentException("TOTP codes must be at least 6 "
+ "digits and no more than 8 digits.");
this.key = new SecretKeySpec(key, "RAW");
this.mode = mode;
this.length = length;
this.startTime = startTime;
this.timeStep = timeStep;
// Verify key validity
getMacInstance(this.mode, this.key);
}
/**
* Creates a new TOTP generator which uses the given shared key to generate
* authentication codes. The provided generation mode dictates the size of
* the key required. The start time and time step used to produce the
* counter value used by HOTP (the algorithm which forms the basis of TOTP)
* are set to the default values recommended by the TOTP specification (0
* and 30 respectively).
*
* @param key
* The shared key to use to generate authentication codes.
*
* @param mode
* The mode in which the TOTP algorithm should operate.
*
* @param length
* The length of the codes to generate, in digits. As required
* by the specification, this value MUST be at least 6 but no greater
* than 8.
*
* @throws InvalidKeyException
* If the provided key is invalid for the requested TOTP mode.
*/
public TOTPGenerator(byte[] key, Mode mode, int length)
throws InvalidKeyException {
this(key, mode, length, DEFAULT_START_TIME, DEFAULT_TIME_STEP);
}
/**
* Returns a new Mac instance which produces message authentication codes
* using the given secret key and the algorithm required by the given TOTP
* mode.
*
* @param mode
* The TOTP mode which dictates the HMAC algorithm to be used.
*
* @param key
* The secret key to use to produce message authentication codes.
*
* @return
* A new Mac instance which produces message authentication codes
* using the given secret key and the algorithm required by the given
* TOTP mode.
*
* @throws InvalidKeyException
* If the provided key is invalid for the requested TOTP mode.
*/
private static Mac getMacInstance(Mode mode, Key key)
throws InvalidKeyException {
try {
Mac hmac = Mac.getInstance(mode.getAlgorithmName());
hmac.init(key);
return hmac;
}
catch (NoSuchAlgorithmException e) {
throw new UnsupportedOperationException("Support for the HMAC "
+ "algorithm required for TOTP in " + mode + " mode is "
+ "missing.", e);
}
}
/**
* Calculates the HMAC for the given message using the key and algorithm
* provided when this TOTPGenerator was created.
*
* @param message
* The message to calculate the HMAC of.
*
* @return
* The HMAC of the given message.
*/
private byte[] getHMAC(byte[] message) {
try {
return getMacInstance(mode, key).doFinal(message);
}
catch (InvalidKeyException e) {
// As the key is verified during construction of the TOTPGenerator,
// this should never happen
throw new IllegalStateException("Provided key became invalid after "
+ "passing validation.", e);
}
}
/**
* Given an arbitrary integer value, returns a code containing the decimal
* representation of that value and exactly the given number of digits. If
* the given value has more than the desired number of digits, leading
* digits will be truncated to reduce the length. If the given value has
* fewer than the desired number of digits, leading zeroes will be added to
* increase the length.
*
* @param value
* The value to convert into a decimal code of the given length.
*
* @param length
* The number of digits to include in the code.
*
* @return
* A code containing the decimal value of the given integer, truncated
* or padded such that exactly the given number of digits are present.
*/
private String toCode(int value, int length) {
// Convert value to simple integer string
String valueString = Integer.toString(value);
// If the resulting string is too long, truncate to the last N digits
if (valueString.length() > length)
return valueString.substring(valueString.length() - length);
// Otherwise, add zeroes until the desired length is reached
StringBuilder builder = new StringBuilder(length);
for (int i = valueString.length(); i < length; i++)
builder.append('0');
// Return the padded integer string
builder.append(valueString);
return builder.toString();
}
/**
* Generates a TOTP code of the given length using the given absolute
* timestamp rather than the current system time.
*
* @param time
* The absolute timestamp to use to generate the TOTP code, in seconds
* since midnight, 1970-01-01, UTC (UNIX epoch).
*
* @return
* The TOTP code which corresponds to the given timestamp, having
* exactly the given length.
*
* @throws IllegalArgumentException
* If the given length is invalid as defined by the TOTP specification.
*/
public String generate(long time) {
// Calculate HOTP counter value based on provided time
long counter = (time - startTime) / timeStep;
byte[] hash = getHMAC(Longs.toByteArray(counter));
// Calculate HOTP value as defined by section 5.2 of RFC 4226:
// https://tools.ietf.org/html/rfc4226#section-5.2
int offset = hash[hash.length - 1] & 0xF;
int binary
= ((hash[offset] & 0x7F) << 24)
| ((hash[offset + 1] & 0xFF) << 16)
| ((hash[offset + 2] & 0xFF) << 8)
| (hash[offset + 3] & 0xFF);
// Truncate or pad the value accordingly
return toCode(binary, length);
}
/**
* Generates a TOTP code of the given length using the current system time.
*
* @return
* The TOTP code which corresponds to the current system time, having
* exactly the given length.
*
* @throws IllegalArgumentException
* If the given length is invalid as defined by the TOTP specification.
*/
public String generate() {
return generate(System.currentTimeMillis() / 1000);
}
/**
* Returns the TOTP code which would have been generated immediately prior
* to the code returned by invoking generate() with the given timestamp.
*
* @param time
* The absolute timestamp to use to generate the TOTP code, in seconds
* since midnight, 1970-01-01, UTC (UNIX epoch).
*
* @return
* The TOTP code which would have been generated immediately prior to
* the the code returned by invoking generate() with the given
* timestamp.
*/
public String previous(long time) {
return generate(Math.max(startTime, time - timeStep));
}
/**
* Returns the TOTP code which would have been generated immediately prior
* to the code currently being returned by generate().
*
* @return
* The TOTP code which would have been generated immediately prior to
* the code currently being returned by generate().
*/
public String previous() {
return previous(System.currentTimeMillis() / 1000);
}
}

View File

@@ -0,0 +1,33 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Config block which registers TOTP-specific field types.
*/
angular.module('guacTOTP').config(['formServiceProvider',
function guacTOTPConfig(formServiceProvider) {
// Define field for the TOTP code provided by the user
formServiceProvider.registerFieldType('GUAC_TOTP_CODE', {
module : 'guacTOTP',
controller : 'authenticationCodeFieldController',
templateUrl : 'app/ext/totp/templates/authenticationCodeField.html'
});
}]);

View File

@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Controller for the "GUAC_TOTP_CODE" field which prompts the user to enter
* the code generated by their authentication device.
*/
angular.module('guacTOTP').controller('authenticationCodeFieldController', ['$scope', '$window',
function authenticationCodeFieldController($scope, $window) {
/**
* The secret key split into groups of at most four characters each, or
* null if the secret key is not exposed.
*
* @type String[]
*/
$scope.groupedSecret = $scope.field.secret && $scope.field.secret.match(/.{1,4}/g);
/**
* Whether the raw details of the secret key and TOTP configuration should
* be shown. By default, such details are hidden. If the secret key is not
* exposed, this property has no effect.
*/
$scope.detailsShown = false;
/**
* Shows the raw details of the secret key and TOTP configuration. If the
* secret key is not exposed, or the details are already shown, this
* function has no effect.
*/
$scope.showDetails = function showDetails() {
$scope.detailsShown = true;
};
/**
* Hides the raw details of the secret key and TOTP configuration. If the
* details are already hidden, this function has no effect.
*/
$scope.hideDetails = function hideDetails() {
$scope.detailsShown = false;
};
/**
* Attempts to open the "otpauth" URI containing the user's TOTP key,
* invoking whichever application may be installed locally for handling
* multi-factor authentication.
*/
$scope.openKeyURI = function openKeyURI() {
$window.open($scope.field.keyUri);
};
}]);

View File

@@ -0,0 +1,28 @@
{
"guacamoleVersion" : "0.9.14",
"name" : "TOTP TFA Authentication Backend",
"namespace" : "totp",
"authProviders" : [
"org.apache.guacamole.auth.totp.TOTPAuthenticationProvider"
],
"translations" : [
"translations/en.json"
],
"js" : [
"totp.min.js"
],
"css" : [
"totp.min.css"
],
"resources" : {
"templates/authenticationCodeField.html" : "text/html"
}
}

View File

@@ -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.
*/

View File

@@ -0,0 +1,88 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
.totp-enroll p, .totp-details {
font-size: 0.8em;
}
.totp-qr-code {
text-align: center;
}
.totp-qr-code img {
margin: 1em;
border: 1px solid rgba(0,0,0,0.25);
box-shadow: 1px 1px 2px rgba(0,0,0,0.25);
cursor: pointer;
}
h3.totp-details-header {
font-size: 0.8em;
}
h3.totp-details-header::before {
content: '▸ ';
}
.totp-details-visible h3.totp-details-header::before {
content: '▾ ';
}
.totp-details,
.totp-hide-details {
display: none;
}
.totp-details-visible .totp-details {
display: table;
}
.totp-details-visible .totp-hide-details {
display: inline;
}
.totp-details-visible .totp-show-details {
display: none;
}
.totp-hide-details, .totp-show-details {
color: blue;
text-decoration: underline;
cursor: pointer;
margin: 0 0.25em;
font-weight: normal;
}
.totp-details {
margin: 0 auto;
}
.totp-details th {
padding-right: 0.25em;
text-align: left;
}
.totp-details td {
font-family: monospace;
}
.totp-detail {
display: inline-block;
margin: 0 0.25em;
}

View File

@@ -0,0 +1,47 @@
<div class="totp-code-field" ng-class="{ 'totp-details-visible' : detailsShown }">
<!-- Enroll user if necessary -->
<div class="totp-enroll" ng-show="field.qrCode">
<p translate="TOTP.HELP_ENROLL_BARCODE"></p>
<!-- Barcode and key details -->
<div class="totp-qr-code"><img ng-src="{{field.qrCode}}" ng-click="openKeyURI()"></div>
<h3 class="totp-details-header">
{{'TOTP.SECTION_HEADER_DETAILS' | translate}}
<a class="totp-show-details" ng-click="showDetails()">{{'TOTP.ACTION_SHOW_DETAILS' | translate}}</a>
<a class="totp-hide-details" ng-click="hideDetails()">{{'TOTP.ACTION_HIDE_DETAILS' | translate}}</a>
</h3>
<table class="totp-details">
<tr>
<th>{{'TOTP.FIELD_HEADER_SECRET_KEY' | translate}}</th>
<td><span ng-repeat="group in groupedSecret"
class="totp-detail">{{ group }}</span></td>
</tr>
<tr>
<th>{{'TOTP.FIELD_HEADER_DIGITS' | translate}}</th>
<td><span class="totp-detail">{{ field.digits }}</span></td>
</tr>
<tr>
<th>{{'TOTP.FIELD_HEADER_ALGORITHM' | translate}}</th>
<td><span class="totp-detail">{{ field.mode }}</span></td>
</tr>
<tr>
<th>{{'TOTP.FIELD_HEADER_INTERVAL' | translate}}</th>
<td><span class="totp-detail">{{ field.period }}</span></td>
</tr>
</table>
<p translate="TOTP.HELP_ENROLL_VERIFY"
translate-values="{ DIGITS : field.digits }"></p>
</div>
<!-- Field for entry of the current TOTP code -->
<div class="totp-code">
<input type="text"
placeholder="{{'TOTP.FIELD_PLACEHOLDER_CODE' |translate}}"
ng-model="model" autocorrect="off" autocapitalize="off"/>
</div>
</div>

View File

@@ -0,0 +1,28 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
/**
* Module which provides handling for TOTP multi-factor authentication.
*/
angular.module('guacTOTP', [
'form'
]);
// Ensure the guacTOTP module is loaded along with the rest of the app
angular.module('index').requires.push('guacTOTP');

View File

@@ -0,0 +1,34 @@
{
"DATA_SOURCE_TOTP" : {
"NAME" : "TOTP TFA Backend"
},
"LOGIN" : {
"FIELD_HEADER_GUAC_TOTP" : ""
},
"TOTP" : {
"ACTION_HIDE_DETAILS" : "Hide",
"ACTION_SHOW_DETAILS" : "Show",
"FIELD_HEADER_ALGORITHM" : "Algorithm:",
"FIELD_HEADER_DIGITS" : "Digits:",
"FIELD_HEADER_INTERVAL" : "Interval:",
"FIELD_HEADER_SECRET_KEY" : "Secret Key:",
"FIELD_PLACEHOLDER_CODE" : "Authentication Code",
"INFO_CODE_REQUIRED" : "Please enter your authentication code to verify your identity.",
"INFO_ENROLL_REQUIRED" : "Multi-factor authentication has been enabled on your account.",
"INFO_VERIFICATION_FAILED" : "Verification failed. Please try again.",
"HELP_ENROLL_BARCODE" : "To complete the enrollment process, scan the barcode below with the two-factor authentication app on your phone or device.",
"HELP_ENROLL_VERIFY" : "After scanning the barcode, enter the {DIGITS}-digit authentication code displayed to verify that enrollment was successful.",
"SECTION_HEADER_DETAILS" : "Details:"
}
}

View File

@@ -0,0 +1,168 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.guacamole.totp;
import java.security.InvalidKeyException;
import org.junit.Test;
import static org.junit.Assert.*;
/*
* NOTE: The tests for this TOTP implementation is based on the TOTP reference
* implementation provided by the IETF Trust at:
*
* https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Reference-Impl
*/
/*
* Copyright (c) 2011 IETF Trust and the persons identified as authors
* of the code. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* - Neither the name of Internet Society, IETF or IETF Trust, nor the names
* of specific contributors, may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS”
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
/**
* Test which verifies the correctness of the TOTPGenerator class against the
* test inputs and results provided in the IETF reference implementation and
* spec for TOTP:
*
* https://tools.ietf.org/id/draft-mraihi-totp-timebased-07.html#Section-Test-Vectors
*/
public class TOTPGeneratorTest {
/**
* Verifies the results of generating authentication codes using the TOTP
* algorithm in SHA1 mode.
*/
@Test
public void testGenerateSHA1() {
// 160-bit key consisting of the bytes "12345678901234567890" repeated
// as necessary
final byte[] key = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0'
};
try {
final TOTPGenerator totp = new TOTPGenerator(key, TOTPGenerator.Mode.SHA1, 8);
assertEquals("94287082", totp.generate(59));
assertEquals("07081804", totp.generate(1111111109));
assertEquals("14050471", totp.generate(1111111111));
assertEquals("89005924", totp.generate(1234567890));
assertEquals("69279037", totp.generate(2000000000));
assertEquals("65353130", totp.generate(20000000000L));
}
catch (InvalidKeyException e) {
fail("SHA1 test key is invalid.");
}
}
/**
* Verifies the results of generating authentication codes using the TOTP
* algorithm in SHA256 mode.
*/
@Test
public void testGenerateSHA256() {
// 256-bit key consisting of the bytes "12345678901234567890" repeated
// as necessary
final byte[] key = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2'
};
try {
final TOTPGenerator totp = new TOTPGenerator(key, TOTPGenerator.Mode.SHA256, 8);
assertEquals("46119246", totp.generate(59));
assertEquals("68084774", totp.generate(1111111109));
assertEquals("67062674", totp.generate(1111111111));
assertEquals("91819424", totp.generate(1234567890));
assertEquals("90698825", totp.generate(2000000000));
assertEquals("77737706", totp.generate(20000000000L));
}
catch (InvalidKeyException e) {
fail("SHA256 test key is invalid.");
}
}
/**
* Verifies the results of generating authentication codes using the TOTP
* algorithm in SHA512 mode.
*/
@Test
public void testGenerateSHA512() {
// 512-bit key consisting of the bytes "12345678901234567890" repeated
// as necessary
final byte[] key = {
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4', '5', '6', '7', '8', '9', '0',
'1', '2', '3', '4'
};
try {
final TOTPGenerator totp = new TOTPGenerator(key, TOTPGenerator.Mode.SHA512, 8);
assertEquals("90693936", totp.generate(59));
assertEquals("25091201", totp.generate(1111111109));
assertEquals("99943326", totp.generate(1111111111));
assertEquals("93441116", totp.generate(1234567890));
assertEquals("38618901", totp.generate(2000000000));
assertEquals("47863826", totp.generate(20000000000L));
}
catch (InvalidKeyException e) {
fail("SHA512 test key is invalid.");
}
}
}

View File

@@ -20,7 +20,7 @@
div.login-ui { div.login-ui {
height: 100%; height: 100%;
width: 100%; width: 100%;
position: fixed; position: absolute;
left: 0; left: 0;
top: 0; top: 0;
display: table; display: table;

View File

@@ -55,6 +55,7 @@
<module>extensions/guacamole-auth-jdbc</module> <module>extensions/guacamole-auth-jdbc</module>
<module>extensions/guacamole-auth-ldap</module> <module>extensions/guacamole-auth-ldap</module>
<module>extensions/guacamole-auth-openid</module> <module>extensions/guacamole-auth-openid</module>
<module>extensions/guacamole-auth-totp</module>
<!-- Example web applications using the Guacamole APIs --> <!-- Example web applications using the Guacamole APIs -->
<module>doc/guacamole-example</module> <module>doc/guacamole-example</module>