mirror of
https://github.com/gyurix1968/guacamole-client.git
synced 2025-09-06 13:17:41 +00:00
GUACAMOLE-1289: Merge upgrade to Duo API v4.
This commit is contained in:
17
doc/licenses/apache-commons-codec-1.11/NOTICE
Normal file
17
doc/licenses/apache-commons-codec-1.11/NOTICE
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
Apache Commons Codec
|
||||||
|
Copyright 2002-2020 The Apache Software Foundation
|
||||||
|
|
||||||
|
This product includes software developed at
|
||||||
|
The Apache Software Foundation (https://www.apache.org/).
|
||||||
|
|
||||||
|
src/test/org/apache/commons/codec/language/DoubleMetaphoneTest.java
|
||||||
|
contains test data from http://aspell.net/test/orig/batch0.tab.
|
||||||
|
Copyright (C) 2002 Kevin Atkinson (kevina@gnu.org)
|
||||||
|
|
||||||
|
===============================================================================
|
||||||
|
|
||||||
|
The content of package org.apache.commons.codec.language.bm has been translated
|
||||||
|
from the original php source code available at http://stevemorse.org/phoneticinfo.htm
|
||||||
|
with permission from the original authors.
|
||||||
|
Original source copyright:
|
||||||
|
Copyright (c) 2008 Alexander Beider & Stephen P. Morse.
|
8
doc/licenses/apache-commons-codec-1.11/README
Normal file
8
doc/licenses/apache-commons-codec-1.11/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Apache Commons Codec (http://commons.apache.org/proper/commons-codec/)
|
||||||
|
-----------------------------------------------------------------------
|
||||||
|
|
||||||
|
Version: 1.11
|
||||||
|
From: 'Apache Software Foundation' (https://www.apache.org/)
|
||||||
|
License(s):
|
||||||
|
Apache v2.0
|
||||||
|
|
@@ -0,0 +1 @@
|
|||||||
|
commons-codec:commons-codec:jar:1.11
|
25
doc/licenses/duo-universal-sdk-1.1.3/LICENSE
Normal file
25
doc/licenses/duo-universal-sdk-1.1.3/LICENSE
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
Copyright (c) 2022 Cisco Systems, Inc. and/or its affiliates
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without
|
||||||
|
modification, are permitted provided that the following conditions
|
||||||
|
are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer.
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
notice, this list of conditions and the following disclaimer in the
|
||||||
|
documentation and/or other materials provided with the distribution.
|
||||||
|
3. The name of the author may not be used to endorse or promote products
|
||||||
|
derived from this software without specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
8
doc/licenses/duo-universal-sdk-1.1.3/README
Normal file
8
doc/licenses/duo-universal-sdk-1.1.3/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Duo Universal SDK for Java (https://duo.com/docs/duoweb)
|
||||||
|
--------------------------------------------------------
|
||||||
|
|
||||||
|
Version: 1.1.3
|
||||||
|
From: 'Cisco Systems'
|
||||||
|
License(s):
|
||||||
|
Duo License (bundled/duo-universal-sdk-1.1.3/LICENSE)
|
||||||
|
|
1
doc/licenses/duo-universal-sdk-1.1.3/dep-coordinates.txt
Normal file
1
doc/licenses/duo-universal-sdk-1.1.3/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.duosecurity:duo-universal-sdk:jar:1.1.3
|
21
doc/licenses/java-jwt-3.3.0/LICENSE
Normal file
21
doc/licenses/java-jwt-3.3.0/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
The MIT License (MIT)
|
||||||
|
|
||||||
|
Copyright (c) 2015 Auth0, Inc. <support@auth0.com> (http://auth0.com)
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
8
doc/licenses/java-jwt-3.3.0/README
Normal file
8
doc/licenses/java-jwt-3.3.0/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Java JWT (https://github.com/auth0/java-jwt)
|
||||||
|
--------------------------------------------
|
||||||
|
|
||||||
|
Version: 3.3.0
|
||||||
|
From: 'Auth0 by Okta' (https://www.auth0.com)
|
||||||
|
License(s):
|
||||||
|
MIT (bundled/java-jwt-3.3.0/LICENSE)
|
||||||
|
|
1
doc/licenses/java-jwt-3.3.0/dep-coordinates.txt
Normal file
1
doc/licenses/java-jwt-3.3.0/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.auth0:java-jwt:jar:3.3.0
|
2
doc/licenses/kotlin-1.4.10/NOTICE.txt
Normal file
2
doc/licenses/kotlin-1.4.10/NOTICE.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
Kotlin Compiler
|
||||||
|
Copyright 2010-2023 JetBrains s.r.o and respective authors and developers
|
8
doc/licenses/kotlin-1.4.10/README
Normal file
8
doc/licenses/kotlin-1.4.10/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
Kotlin (https://kotlinlang.org/)
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Version: 1.4.10
|
||||||
|
From: 'JetBrains s.r.o and respective authors and developers'
|
||||||
|
License(s):
|
||||||
|
Apache v2.0
|
||||||
|
|
5
doc/licenses/kotlin-1.4.10/dep-coordinates.txt
Normal file
5
doc/licenses/kotlin-1.4.10/dep-coordinates.txt
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
org.jetbrains.kotlin:kotlin-reflect:jar:1.4.10
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib:jar:1.4.10
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-common:jar:1.4.10
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk8:jar:1.4.10
|
||||||
|
org.jetbrains.kotlin:kotlin-stdlib-jdk7:jar:1.4.10
|
201
doc/licenses/logging-interceptor-4.9.1/LICENSE.txt
Normal file
201
doc/licenses/logging-interceptor-4.9.1/LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
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.
|
13
doc/licenses/logging-interceptor-4.9.1/NOTICE
Normal file
13
doc/licenses/logging-interceptor-4.9.1/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2019 Square, Inc.
|
||||||
|
|
||||||
|
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.
|
8
doc/licenses/logging-interceptor-4.9.1/README
Normal file
8
doc/licenses/logging-interceptor-4.9.1/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
okhttp logging-interceptor (https://square.github.io/okhttp/)
|
||||||
|
-------------------------------------------------------------
|
||||||
|
|
||||||
|
Version: 4.9.1
|
||||||
|
From: 'Square Inc'
|
||||||
|
License(s):
|
||||||
|
Apache v2.0
|
||||||
|
|
@@ -0,0 +1 @@
|
|||||||
|
com.squareup.okhttp3:logging-interceptor:jar:4.9.1
|
201
doc/licenses/okhttp-3.14.9/LICENSE.txt
Normal file
201
doc/licenses/okhttp-3.14.9/LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
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.
|
13
doc/licenses/okhttp-3.14.9/NOTICE
Normal file
13
doc/licenses/okhttp-3.14.9/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2019 Square, Inc.
|
||||||
|
|
||||||
|
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.
|
7
doc/licenses/okhttp-3.14.9/README
Normal file
7
doc/licenses/okhttp-3.14.9/README
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
okhttp (https://square.github.io/okhttp/)
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Version: 3.14.9
|
||||||
|
From: 'Square Inc'
|
||||||
|
License(s):
|
||||||
|
Apache 2.0
|
1
doc/licenses/okhttp-3.14.9/dep-coordinates.txt
Normal file
1
doc/licenses/okhttp-3.14.9/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.squareup.okhttp3:okhttp:jar:3.14.9
|
201
doc/licenses/okhttp-4.9.1/LICENSE.txt
Normal file
201
doc/licenses/okhttp-4.9.1/LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
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.
|
13
doc/licenses/okhttp-4.9.1/NOTICE
Normal file
13
doc/licenses/okhttp-4.9.1/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2021 Square, Inc.
|
||||||
|
|
||||||
|
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.
|
7
doc/licenses/okhttp-4.9.1/README
Normal file
7
doc/licenses/okhttp-4.9.1/README
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
okhttp (https://square.github.io/okhttp/)
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Version: 4.9.1
|
||||||
|
From: 'Square Inc'
|
||||||
|
License(s):
|
||||||
|
Apache 2.0
|
1
doc/licenses/okhttp-4.9.1/dep-coordinates.txt
Normal file
1
doc/licenses/okhttp-4.9.1/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.squareup.okhttp3:okhttp:jar:4.9.1
|
201
doc/licenses/okio-1.17.2/LICENSE.txt
Normal file
201
doc/licenses/okio-1.17.2/LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
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.
|
13
doc/licenses/okio-1.17.2/NOTICE
Normal file
13
doc/licenses/okio-1.17.2/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2013 Square, Inc.
|
||||||
|
|
||||||
|
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.
|
7
doc/licenses/okio-1.17.2/README
Normal file
7
doc/licenses/okio-1.17.2/README
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
okio (https://square.github.io/okio/)
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Version: 1.17.2
|
||||||
|
From: 'Square Inc'
|
||||||
|
License(s):
|
||||||
|
Apache 2.0 (bundled/retrofit-2.9.0/LICENSE.txt)
|
1
doc/licenses/okio-1.17.2/dep-coordinates.txt
Normal file
1
doc/licenses/okio-1.17.2/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.squareup.okio:okio:jar:1.17.2
|
201
doc/licenses/okio-2.8.0/LICENSE.txt
Normal file
201
doc/licenses/okio-2.8.0/LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
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.
|
13
doc/licenses/okio-2.8.0/NOTICE
Normal file
13
doc/licenses/okio-2.8.0/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2020 Square, Inc.
|
||||||
|
|
||||||
|
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.
|
7
doc/licenses/okio-2.8.0/README
Normal file
7
doc/licenses/okio-2.8.0/README
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
okio (https://square.github.io/okio/)
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Version: 2.8.0
|
||||||
|
From: 'Square Inc'
|
||||||
|
License(s):
|
||||||
|
Apache 2.0 (bundled/retrofit-2.9.0/LICENSE.txt)
|
1
doc/licenses/okio-2.8.0/dep-coordinates.txt
Normal file
1
doc/licenses/okio-2.8.0/dep-coordinates.txt
Normal file
@@ -0,0 +1 @@
|
|||||||
|
com.squareup.okio:okio:jar:2.8.0
|
201
doc/licenses/retrofit-2.9.0/LICENSE.txt
Normal file
201
doc/licenses/retrofit-2.9.0/LICENSE.txt
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
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.
|
13
doc/licenses/retrofit-2.9.0/NOTICE
Normal file
13
doc/licenses/retrofit-2.9.0/NOTICE
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
Copyright 2013 Square, Inc.
|
||||||
|
|
||||||
|
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.
|
8
doc/licenses/retrofit-2.9.0/README
Normal file
8
doc/licenses/retrofit-2.9.0/README
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
retrofit (https://square.github.io/retrofit/)
|
||||||
|
---------------------------------------------
|
||||||
|
|
||||||
|
Version: 2.9.0
|
||||||
|
From: 'Square Inc'
|
||||||
|
License(s):
|
||||||
|
Apache 2.0 (bundled/retrofit-2.9.0/LICENSE.txt)
|
||||||
|
|
2
doc/licenses/retrofit-2.9.0/dep-coordinates.txt
Normal file
2
doc/licenses/retrofit-2.9.0/dep-coordinates.txt
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
com.squareup.retrofit2:retrofit:jar:2.9.0
|
||||||
|
com.squareup.retrofit2:converter-jackson:jar:2.9.0
|
202
doc/licenses/spring-web-5.3.25/LICENSE
Normal file
202
doc/licenses/spring-web-5.3.25/LICENSE
Normal file
@@ -0,0 +1,202 @@
|
|||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
https://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
|
||||||
|
|
||||||
|
https://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.
|
7
doc/licenses/spring-web-5.3.25/README
Normal file
7
doc/licenses/spring-web-5.3.25/README
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
Spring Framework (https://spring.io/projects/spring-framework)
|
||||||
|
--------------------------------------------------------------
|
||||||
|
|
||||||
|
Version: 5.3.25
|
||||||
|
From: 'Spring' (https://spring.io/)
|
||||||
|
License(s):
|
||||||
|
Apache v2.0
|
4
doc/licenses/spring-web-5.3.25/dep-coordinates.txt
Normal file
4
doc/licenses/spring-web-5.3.25/dep-coordinates.txt
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
org.springframework:spring-web:jar:5.3.25
|
||||||
|
org.springframework:spring-beans:jar:5.3.25
|
||||||
|
org.springframework:spring-core:jar:5.3.25
|
||||||
|
org.springframework:spring-jcl:jar:5.3.25
|
@@ -41,90 +41,30 @@
|
|||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
</properties>
|
</properties>
|
||||||
|
|
||||||
<build>
|
<dependencyManagement>
|
||||||
<plugins>
|
<dependencies>
|
||||||
|
<!-- Define okhttp version to use everywhere to resolve conflict -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.squareup.okhttp3</groupId>
|
||||||
|
<artifactId>okhttp</artifactId>
|
||||||
|
<version>4.9.1</version> <!-- Specify the desired version -->
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- Pre-cache Angular templates with maven-angular-plugin -->
|
<!-- Force the use of a consistent version of Kotlin standard library common -->
|
||||||
<plugin>
|
<dependency>
|
||||||
<groupId>com.keithbranton.mojo</groupId>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<artifactId>angular-maven-plugin</artifactId>
|
<artifactId>kotlin-stdlib-common</artifactId>
|
||||||
<version>0.3.4</version>
|
<version>1.4.10</version>
|
||||||
<executions>
|
</dependency>
|
||||||
<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/duo</prefix>
|
|
||||||
</configuration>
|
|
||||||
</plugin>
|
|
||||||
|
|
||||||
<!-- JS/CSS Minification Plugin -->
|
<dependency>
|
||||||
<plugin>
|
<groupId>org.jetbrains.kotlin</groupId>
|
||||||
<groupId>com.github.buckelieg</groupId>
|
<artifactId>kotlin-stdlib</artifactId>
|
||||||
<artifactId>minify-maven-plugin</artifactId>
|
<version>1.4.10</version>
|
||||||
<executions>
|
</dependency>
|
||||||
<execution>
|
|
||||||
<id>default-cli</id>
|
|
||||||
<configuration>
|
|
||||||
<charset>UTF-8</charset>
|
|
||||||
|
|
||||||
<webappSourceDir>${basedir}/src/main/resources</webappSourceDir>
|
</dependencies>
|
||||||
<webappTargetDir>${project.build.directory}/classes</webappTargetDir>
|
</dependencyManagement>
|
||||||
|
|
||||||
<cssSourceDir>/</cssSourceDir>
|
|
||||||
<cssTargetDir>/</cssTargetDir>
|
|
||||||
<cssFinalFile>duo.css</cssFinalFile>
|
|
||||||
|
|
||||||
<cssSourceFiles>
|
|
||||||
<cssSourceFile>license.txt</cssSourceFile>
|
|
||||||
</cssSourceFiles>
|
|
||||||
|
|
||||||
<cssSourceIncludes>
|
|
||||||
<cssSourceInclude>**/*.css</cssSourceInclude>
|
|
||||||
</cssSourceIncludes>
|
|
||||||
|
|
||||||
<jsSourceDir>/</jsSourceDir>
|
|
||||||
<jsTargetDir>/</jsTargetDir>
|
|
||||||
<jsFinalFile>duo.js</jsFinalFile>
|
|
||||||
|
|
||||||
<jsSourceFiles>
|
|
||||||
<jsSourceFile>license.txt</jsSourceFile>
|
|
||||||
<jsSourceFile>lib/DuoWeb/LICENSE.js</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>
|
|
||||||
|
|
||||||
</plugins>
|
|
||||||
</build>
|
|
||||||
|
|
||||||
<dependencies>
|
<dependencies>
|
||||||
|
|
||||||
@@ -156,6 +96,20 @@
|
|||||||
<scope>provided</scope>
|
<scope>provided</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
|
<!-- Duo SDK -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>com.duosecurity</groupId>
|
||||||
|
<artifactId>duo-universal-sdk</artifactId>
|
||||||
|
<version>1.1.3</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<!-- spring-web -->
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework</groupId>
|
||||||
|
<artifactId>spring-web</artifactId>
|
||||||
|
<version>5.3.25</version>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
</project>
|
</project>
|
||||||
|
@@ -33,6 +33,13 @@ import org.apache.guacamole.net.auth.UserContext;
|
|||||||
*/
|
*/
|
||||||
public class DuoAuthenticationProvider extends AbstractAuthenticationProvider {
|
public class DuoAuthenticationProvider extends AbstractAuthenticationProvider {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier for this authentication provider. This is used in
|
||||||
|
* various parts of the Guacamole client to distinguish this provider from
|
||||||
|
* others, particularly when multiple authentication providers are used.
|
||||||
|
*/
|
||||||
|
public static String PROVIDER_IDENTIFER = "duo";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Injector which will manage the object graph of this authentication
|
* Injector which will manage the object graph of this authentication
|
||||||
* provider.
|
* provider.
|
||||||
@@ -58,7 +65,7 @@ public class DuoAuthenticationProvider extends AbstractAuthenticationProvider {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getIdentifier() {
|
public String getIdentifier() {
|
||||||
return "duo";
|
return PROVIDER_IDENTIFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@@ -21,7 +21,6 @@ package org.apache.guacamole.auth.duo;
|
|||||||
|
|
||||||
import com.google.inject.AbstractModule;
|
import com.google.inject.AbstractModule;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.auth.duo.api.DuoService;
|
|
||||||
import org.apache.guacamole.auth.duo.conf.ConfigurationService;
|
import org.apache.guacamole.auth.duo.conf.ConfigurationService;
|
||||||
import org.apache.guacamole.environment.Environment;
|
import org.apache.guacamole.environment.Environment;
|
||||||
import org.apache.guacamole.environment.LocalEnvironment;
|
import org.apache.guacamole.environment.LocalEnvironment;
|
||||||
@@ -62,7 +61,6 @@ public class DuoAuthenticationProviderModule extends AbstractModule {
|
|||||||
|
|
||||||
// Store associated auth provider
|
// Store associated auth provider
|
||||||
this.authProvider = authProvider;
|
this.authProvider = authProvider;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -74,9 +72,7 @@ public class DuoAuthenticationProviderModule extends AbstractModule {
|
|||||||
|
|
||||||
// Bind Duo-specific services
|
// Bind Duo-specific services
|
||||||
bind(ConfigurationService.class);
|
bind(ConfigurationService.class);
|
||||||
bind(DuoService.class);
|
|
||||||
bind(UserVerificationService.class);
|
bind(UserVerificationService.class);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -19,37 +19,59 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.duo;
|
package org.apache.guacamole.auth.duo;
|
||||||
|
|
||||||
|
import com.duosecurity.Client;
|
||||||
|
import com.duosecurity.exception.DuoException;
|
||||||
|
import com.duosecurity.model.Token;
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.auth.duo.api.DuoService;
|
import org.apache.guacamole.GuacamoleServerException;
|
||||||
import org.apache.guacamole.auth.duo.conf.ConfigurationService;
|
import org.apache.guacamole.auth.duo.conf.ConfigurationService;
|
||||||
import org.apache.guacamole.auth.duo.form.DuoSignedResponseField;
|
import org.apache.guacamole.form.RedirectField;
|
||||||
import org.apache.guacamole.form.Field;
|
|
||||||
import org.apache.guacamole.language.TranslatableGuacamoleClientException;
|
import org.apache.guacamole.language.TranslatableGuacamoleClientException;
|
||||||
import org.apache.guacamole.language.TranslatableGuacamoleInsufficientCredentialsException;
|
import org.apache.guacamole.language.TranslatableGuacamoleInsufficientCredentialsException;
|
||||||
|
import org.apache.guacamole.language.TranslatableMessage;
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
import org.apache.guacamole.net.auth.credentials.CredentialsInfo;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.web.util.UriComponentsBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for verifying the identity of a user against Duo.
|
* Service for verifying the identity of a user against Duo.
|
||||||
*/
|
*/
|
||||||
public class UserVerificationService {
|
public class UserVerificationService {
|
||||||
|
|
||||||
|
private static final Logger logger = LoggerFactory.getLogger(UserVerificationService.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter which Duo will return in it's GET call-back
|
||||||
|
* that contains the code that the client will use to generate a token.
|
||||||
|
*/
|
||||||
|
public static final String DUO_CODE_PARAMETER_NAME = "duo_code";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name of the parameter that will be used in the GET call-back that
|
||||||
|
* contains the session state.
|
||||||
|
*/
|
||||||
|
public static final String DUO_STATE_PARAMETER_NAME = "state";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The value that will be returned in the token if Duo authentication
|
||||||
|
* was successful.
|
||||||
|
*/
|
||||||
|
private static final String DUO_TOKEN_SUCCESS_VALUE = "allow";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for retrieving Duo configuration information.
|
* Service for retrieving Duo configuration information.
|
||||||
*/
|
*/
|
||||||
@Inject
|
@Inject
|
||||||
private ConfigurationService confService;
|
private ConfigurationService confService;
|
||||||
|
|
||||||
/**
|
|
||||||
* Service for verifying users against Duo.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private DuoService duoService;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verifies the identity of the given user via the Duo multi-factor
|
* Verifies the identity of the given user via the Duo multi-factor
|
||||||
* authentication service. If a signed response from Duo has not already
|
* authentication service. If a signed response from Duo has not already
|
||||||
@@ -76,38 +98,71 @@ public class UserVerificationService {
|
|||||||
if (authenticatedUser.getIdentifier().equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER))
|
if (authenticatedUser.getIdentifier().equals(AuthenticatedUser.ANONYMOUS_IDENTIFIER))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// Retrieve signed Duo response from request
|
String username = authenticatedUser.getIdentifier();
|
||||||
String signedResponse = request.getParameter(DuoSignedResponseField.PARAMETER_NAME);
|
|
||||||
|
|
||||||
// If no signed response, request one
|
try {
|
||||||
if (signedResponse == null) {
|
|
||||||
|
|
||||||
// Create field which requests a signed response from Duo that
|
String redirectUrl = confService.getRedirectUri().toString();
|
||||||
// verifies the identity of the given user via the configured
|
|
||||||
// Duo API endpoint
|
String builtUrl = UriComponentsBuilder
|
||||||
Field signedResponseField = new DuoSignedResponseField(
|
.fromUriString(redirectUrl)
|
||||||
|
.queryParam(Credentials.RESUME_QUERY, DuoAuthenticationProvider.PROVIDER_IDENTIFER)
|
||||||
|
.build()
|
||||||
|
.toUriString();
|
||||||
|
|
||||||
|
// Set up the Duo Client
|
||||||
|
Client duoClient = new Client.Builder(
|
||||||
|
confService.getClientId(),
|
||||||
|
confService.getClientSecret(),
|
||||||
confService.getAPIHostname(),
|
confService.getAPIHostname(),
|
||||||
duoService.createSignedRequest(authenticatedUser));
|
builtUrl)
|
||||||
|
.build();
|
||||||
|
|
||||||
// Create an overall description of the additional credentials
|
duoClient.healthCheck();
|
||||||
// required to verify identity
|
|
||||||
CredentialsInfo expectedCredentials = new CredentialsInfo(
|
// Retrieve signed Duo Code and State from the request
|
||||||
Collections.singletonList(signedResponseField));
|
String duoCode = request.getParameter(DUO_CODE_PARAMETER_NAME);
|
||||||
|
String duoState = request.getParameter(DUO_STATE_PARAMETER_NAME);
|
||||||
|
|
||||||
|
// If no code or state is received, assume Duo MFA redirect has not occured and do it
|
||||||
|
if (duoCode == null || duoState == null) {
|
||||||
|
|
||||||
|
// Get a new session state from the Duo client
|
||||||
|
duoState = duoClient.generateState();
|
||||||
|
long expirationTimestamp = System.currentTimeMillis() + (confService.getAuthTimeout() * 1000L);
|
||||||
|
|
||||||
// Request additional credentials
|
// Request additional credentials
|
||||||
throw new TranslatableGuacamoleInsufficientCredentialsException(
|
throw new TranslatableGuacamoleInsufficientCredentialsException(
|
||||||
"Verification using Duo is required before authentication "
|
"Verification using Duo is required before authentication "
|
||||||
+ "can continue.", "LOGIN.INFO_DUO_AUTH_REQUIRED",
|
+ "can continue.", "LOGIN.INFO_DUO_AUTH_REQUIRED",
|
||||||
expectedCredentials);
|
new CredentialsInfo(Collections.singletonList(
|
||||||
|
new RedirectField(
|
||||||
|
DUO_CODE_PARAMETER_NAME,
|
||||||
|
new URI(duoClient.createAuthUrl(username, duoState)),
|
||||||
|
new TranslatableMessage("LOGIN.INFO_DUO_REDIRECT_PENDING")
|
||||||
|
)
|
||||||
|
)),
|
||||||
|
duoState, DuoAuthenticationProvider.PROVIDER_IDENTIFER,
|
||||||
|
DUO_STATE_PARAMETER_NAME, expirationTimestamp
|
||||||
|
);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// If signed response does not verify this user's identity, abort auth
|
// Get the token from the DuoClient using the code and username, and check status
|
||||||
if (!duoService.isValidSignedResponse(authenticatedUser, signedResponse))
|
Token token = duoClient.exchangeAuthorizationCodeFor2FAResult(duoCode, username);
|
||||||
|
if (token == null
|
||||||
|
|| token.getAuth_result() == null
|
||||||
|
|| !DUO_TOKEN_SUCCESS_VALUE.equals(token.getAuth_result().getStatus()))
|
||||||
throw new TranslatableGuacamoleClientException("Provided Duo "
|
throw new TranslatableGuacamoleClientException("Provided Duo "
|
||||||
+ "validation code is incorrect.",
|
+ "validation code is incorrect.",
|
||||||
"LOGIN.INFO_DUO_VALIDATION_CODE_INCORRECT");
|
"LOGIN.INFO_DUO_VALIDATION_CODE_INCORRECT");
|
||||||
|
}
|
||||||
|
catch (DuoException e) {
|
||||||
|
throw new GuacamoleServerException("Duo Client error.", e);
|
||||||
|
}
|
||||||
|
catch (URISyntaxException e) {
|
||||||
|
throw new GuacamoleServerException("Error creating URI from Duo Authentication URL.", e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,245 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.guacamole.auth.duo.api;
|
|
||||||
|
|
||||||
import com.google.common.io.BaseEncoding;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.apache.guacamole.GuacamoleClientException;
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Data which describes the identity of the user being verified by Duo.
|
|
||||||
*/
|
|
||||||
public class DuoCookie {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pattern which matches valid cookies. Each cookie is made up of three
|
|
||||||
* sections, separated from each other by pipe symbols ("|").
|
|
||||||
*/
|
|
||||||
private static final Pattern COOKIE_FORMAT = Pattern.compile("([^|]+)\\|([^|]+)\\|([0-9]+)");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within COOKIE_FORMAT which contains the
|
|
||||||
* username.
|
|
||||||
*/
|
|
||||||
private static final int USERNAME_GROUP = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within COOKIE_FORMAT which contains the
|
|
||||||
* integration key.
|
|
||||||
*/
|
|
||||||
private static final int INTEGRATION_KEY_GROUP = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within COOKIE_FORMAT which contains the
|
|
||||||
* expiration timestamp.
|
|
||||||
*/
|
|
||||||
private static final int EXPIRATION_TIMESTAMP_GROUP = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The username of the user being verified.
|
|
||||||
*/
|
|
||||||
private final String username;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The integration key provided by Duo and specific to this deployment of
|
|
||||||
* Guacamole.
|
|
||||||
*/
|
|
||||||
private final String integrationKey;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The time that this cookie expires, in seconds since midnight of
|
|
||||||
* 1970-01-01 (UTC).
|
|
||||||
*/
|
|
||||||
private final long expires;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new DuoCookie which describes the identity of a user being
|
|
||||||
* verified.
|
|
||||||
*
|
|
||||||
* @param username
|
|
||||||
* The username of the user being verified.
|
|
||||||
*
|
|
||||||
* @param integrationKey
|
|
||||||
* The integration key provided by Duo and specific to this deployment
|
|
||||||
* of Guacamole.
|
|
||||||
*
|
|
||||||
* @param expires
|
|
||||||
* The time that this cookie expires, in seconds since midnight of
|
|
||||||
* 1970-01-01 (UTC).
|
|
||||||
*/
|
|
||||||
public DuoCookie(String username, String integrationKey, long expires) {
|
|
||||||
this.username = username;
|
|
||||||
this.integrationKey = integrationKey;
|
|
||||||
this.expires = expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the username of the user being verified.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The username of the user being verified.
|
|
||||||
*/
|
|
||||||
public String getUsername() {
|
|
||||||
return username;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the integration key provided by Duo and specific to this
|
|
||||||
* deployment of Guacamole.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The integration key provided by Duo and specific to this deployment
|
|
||||||
* of Guacamole.
|
|
||||||
*/
|
|
||||||
public String getIntegrationKey() {
|
|
||||||
return integrationKey;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the time that this cookie expires. The expiration time is
|
|
||||||
* represented in seconds since midnight of 1970-01-01 (UTC).
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The time that this cookie expires, in seconds since midnight of
|
|
||||||
* 1970-01-01 (UTC).
|
|
||||||
*/
|
|
||||||
public long getExpirationTimestamp(){
|
|
||||||
return expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the current time as the number of seconds elapsed since
|
|
||||||
* midnight of 1970-01-01 (UTC).
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The current time as the number of seconds elapsed since midnight of
|
|
||||||
* 1970-01-01 (UTC).
|
|
||||||
*/
|
|
||||||
public static long currentTimestamp() {
|
|
||||||
return System.currentTimeMillis() / 1000;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether this cookie has expired (the current time has met or
|
|
||||||
* exceeded the expiration timestamp).
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* true if this cookie has expired, false otherwise.
|
|
||||||
*/
|
|
||||||
public boolean isExpired() {
|
|
||||||
return currentTimestamp() >= expires;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a base64-encoded Duo cookie, producing a new DuoCookie object
|
|
||||||
* containing the data therein. If the given string is not a valid Duo
|
|
||||||
* cookie, an exception is thrown. Note that the cookie may be expired, and
|
|
||||||
* must be checked for expiration prior to actual use.
|
|
||||||
*
|
|
||||||
* @param str
|
|
||||||
* The base64-encoded Duo cookie to parse.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* A new DuoCookie object containing the same data as the given
|
|
||||||
* base64-encoded Duo cookie string.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If the given string is not a valid base64-encoded Duo cookie.
|
|
||||||
*/
|
|
||||||
public static DuoCookie parseDuoCookie(String str) throws GuacamoleException {
|
|
||||||
|
|
||||||
// Attempt to decode data as base64
|
|
||||||
String data;
|
|
||||||
try {
|
|
||||||
data = new String(BaseEncoding.base64().decode(str), "UTF-8");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bail if invalid base64 is provided
|
|
||||||
catch (IllegalArgumentException e) {
|
|
||||||
throw new GuacamoleClientException("Username is not correctly "
|
|
||||||
+ "encoded as base64.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throw hard errors if standard pieces of Java are missing
|
|
||||||
catch (UnsupportedEncodingException e) {
|
|
||||||
throw new UnsupportedOperationException("Unexpected lack of "
|
|
||||||
+ "UTF-8 support.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify format of provided data
|
|
||||||
Matcher matcher = COOKIE_FORMAT.matcher(data);
|
|
||||||
if (!matcher.matches())
|
|
||||||
throw new GuacamoleClientException("Format of base64-encoded "
|
|
||||||
+ "username is invalid.");
|
|
||||||
|
|
||||||
// Get username and key (simple strings)
|
|
||||||
String username = matcher.group(USERNAME_GROUP);
|
|
||||||
String key = matcher.group(INTEGRATION_KEY_GROUP);
|
|
||||||
|
|
||||||
// Parse expiration time
|
|
||||||
long expires;
|
|
||||||
try {
|
|
||||||
expires = Long.parseLong(matcher.group(EXPIRATION_TIMESTAMP_GROUP));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Bail if expiration timestamp is not a valid long
|
|
||||||
catch (NumberFormatException e) {
|
|
||||||
throw new GuacamoleClientException("Expiration timestamp is "
|
|
||||||
+ "not valid.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return parsed cookie
|
|
||||||
return new DuoCookie(username, key, expires);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the base64-encoded string representation of this DuoCookie. The
|
|
||||||
* format used is identical to that required by the Duo service: the
|
|
||||||
* username, integration key, and expiration timestamp separated by pipe
|
|
||||||
* symbols ("|") and encoded with base64.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The base64-encoded string representation of this DuoCookie.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Separate each cookie field with pipe symbols
|
|
||||||
String data = username + "|" + integrationKey + "|" + expires;
|
|
||||||
|
|
||||||
// Encode resulting cookie string with base64
|
|
||||||
return BaseEncoding.base64().encode(data.getBytes("UTF-8"));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throw hard errors if standard pieces of Java are missing
|
|
||||||
catch (UnsupportedEncodingException e) {
|
|
||||||
throw new UnsupportedOperationException("Unexpected lack of UTF-8 support.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,205 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.guacamole.auth.duo.api;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
|
||||||
import org.apache.guacamole.auth.duo.conf.ConfigurationService;
|
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service which produces signed requests and parses/verifies signed responses
|
|
||||||
* as required by Duo's API.
|
|
||||||
*/
|
|
||||||
public class DuoService {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Logger for this class.
|
|
||||||
*/
|
|
||||||
private static final Logger logger = LoggerFactory.getLogger(DuoService.class);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pattern which matches valid Duo responses. Each response is made up of
|
|
||||||
* two sections, separated from each other by a colon, where each section
|
|
||||||
* is a signed Duo cookie.
|
|
||||||
*/
|
|
||||||
private static final Pattern RESPONSE_FORMAT = Pattern.compile("([^:]+):([^:]+)");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within RESPONSE_FORMAT which
|
|
||||||
* contains the DUO_RESPONSE cookie signed by the secret key.
|
|
||||||
*/
|
|
||||||
private static final int DUO_COOKIE_GROUP = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within RESPONSE_FORMAT which
|
|
||||||
* contains the APPLICATION cookie signed by the application key.
|
|
||||||
*/
|
|
||||||
private static final int APP_COOKIE_GROUP = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The amount of time that each generated cookie remains valid, in seconds.
|
|
||||||
*/
|
|
||||||
private static final int COOKIE_EXPIRATION_TIME = 300;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Service for retrieving Duo configuration information.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private ConfigurationService confService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates and signs a new request to verify the identity of the given
|
|
||||||
* user. This request may ultimately be sent to Duo, resulting in a signed
|
|
||||||
* response from Duo if that verification succeeds.
|
|
||||||
*
|
|
||||||
* @param authenticatedUser
|
|
||||||
* The user whose identity should be verified.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* A signed user verification request which can be sent to Duo.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If required Duo-specific configuration options are missing or
|
|
||||||
* invalid, or if an error prevents generation of the signature.
|
|
||||||
*/
|
|
||||||
public String createSignedRequest(AuthenticatedUser authenticatedUser)
|
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
// Generate a cookie associating the username with the integration key
|
|
||||||
DuoCookie cookie = new DuoCookie(authenticatedUser.getIdentifier(),
|
|
||||||
confService.getIntegrationKey(),
|
|
||||||
DuoCookie.currentTimestamp() + COOKIE_EXPIRATION_TIME);
|
|
||||||
|
|
||||||
// Sign cookie with secret key
|
|
||||||
SignedDuoCookie duoCookie = new SignedDuoCookie(cookie,
|
|
||||||
SignedDuoCookie.Type.DUO_REQUEST,
|
|
||||||
confService.getSecretKey());
|
|
||||||
|
|
||||||
// Sign cookie with application key
|
|
||||||
SignedDuoCookie appCookie = new SignedDuoCookie(cookie,
|
|
||||||
SignedDuoCookie.Type.APPLICATION,
|
|
||||||
confService.getApplicationKey());
|
|
||||||
|
|
||||||
// Return signed request containing both signed cookies, separated by
|
|
||||||
// a colon (as required by Duo)
|
|
||||||
return duoCookie + ":" + appCookie;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns whether the given signed response is a valid response from Duo
|
|
||||||
* which verifies the identity of the given user. If the given response is
|
|
||||||
* invalid or does not verify the identity of the given user (including if
|
|
||||||
* it is a valid response which verifies the identity of a DIFFERENT user),
|
|
||||||
* false is returned.
|
|
||||||
*
|
|
||||||
* @param authenticatedUser
|
|
||||||
* The user that the given signed response should verify.
|
|
||||||
*
|
|
||||||
* @param signedResponse
|
|
||||||
* The signed response received from Duo in response to a signed
|
|
||||||
* request.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* true if the signed response is a valid response from Duo AND verifies
|
|
||||||
* the identity of the given user, false otherwise.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If required Duo-specific configuration options are missing or
|
|
||||||
* invalid, or if an error occurs prevents validation of the signature.
|
|
||||||
*/
|
|
||||||
public boolean isValidSignedResponse(AuthenticatedUser authenticatedUser,
|
|
||||||
String signedResponse) throws GuacamoleException {
|
|
||||||
|
|
||||||
SignedDuoCookie duoCookie;
|
|
||||||
SignedDuoCookie appCookie;
|
|
||||||
|
|
||||||
// Retrieve username from externally-authenticated user
|
|
||||||
String username = authenticatedUser.getIdentifier();
|
|
||||||
|
|
||||||
// Retrieve Duo-specific keys from configuration
|
|
||||||
String applicationKey = confService.getApplicationKey();
|
|
||||||
String integrationKey = confService.getIntegrationKey();
|
|
||||||
String secretKey = confService.getSecretKey();
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Verify format of response
|
|
||||||
Matcher matcher = RESPONSE_FORMAT.matcher(signedResponse);
|
|
||||||
if (!matcher.matches()) {
|
|
||||||
logger.debug("Duo response is not in correct format.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Parse signed cookie defining the user verified by Duo
|
|
||||||
duoCookie = SignedDuoCookie.parseSignedDuoCookie(secretKey,
|
|
||||||
matcher.group(DUO_COOKIE_GROUP));
|
|
||||||
|
|
||||||
// Parse signed cookie defining the user this application
|
|
||||||
// originally requested
|
|
||||||
appCookie = SignedDuoCookie.parseSignedDuoCookie(applicationKey,
|
|
||||||
matcher.group(APP_COOKIE_GROUP));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Simply return false if signature fails to verify
|
|
||||||
catch (GuacamoleException e) {
|
|
||||||
logger.debug("Duo signature verification failed.", e);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify neither cookie is expired
|
|
||||||
if (duoCookie.isExpired() || appCookie.isExpired()) {
|
|
||||||
logger.debug("Duo response contained expired cookie(s).");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify the cookies in the response have the correct types
|
|
||||||
if (duoCookie.getType() != SignedDuoCookie.Type.DUO_RESPONSE
|
|
||||||
|| appCookie.getType() != SignedDuoCookie.Type.APPLICATION) {
|
|
||||||
logger.debug("Duo response did not contain correct cookie type(s).");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify integration key matches both cookies
|
|
||||||
if (!duoCookie.getIntegrationKey().equals(integrationKey)
|
|
||||||
|| !appCookie.getIntegrationKey().equals(integrationKey)) {
|
|
||||||
logger.debug("Integration key of Duo response is incorrect.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify both cookies are for the current user
|
|
||||||
if (!duoCookie.getUsername().equals(username)
|
|
||||||
|| !appCookie.getUsername().equals(username)) {
|
|
||||||
logger.debug("Username of Duo response is incorrect.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// All verifications tests pass
|
|
||||||
return true;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,332 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.guacamole.auth.duo.api;
|
|
||||||
|
|
||||||
import com.google.common.io.BaseEncoding;
|
|
||||||
import java.io.UnsupportedEncodingException;
|
|
||||||
import java.security.InvalidKeyException;
|
|
||||||
import java.security.NoSuchAlgorithmException;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import javax.crypto.Mac;
|
|
||||||
import javax.crypto.spec.SecretKeySpec;
|
|
||||||
import org.apache.guacamole.GuacamoleClientException;
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A DuoCookie which is cryptographically signed with a provided key using
|
|
||||||
* HMAC-SHA1.
|
|
||||||
*/
|
|
||||||
public class SignedDuoCookie extends DuoCookie {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Pattern which matches valid signed cookies. Like unsigned cookies, each
|
|
||||||
* signed cookie is made up of three sections, separated from each other by
|
|
||||||
* pipe symbols ("|").
|
|
||||||
*/
|
|
||||||
private static final Pattern SIGNED_COOKIE_FORMAT = Pattern.compile("([^|]+)\\|([^|]+)\\|([0-9a-f]+)");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within SIGNED_COOKIE_FORMAT which
|
|
||||||
* contains the cookie type prefix.
|
|
||||||
*/
|
|
||||||
private static final int PREFIX_GROUP = 1;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within SIGNED_COOKIE_FORMAT which
|
|
||||||
* contains the cookie's base64-encoded data.
|
|
||||||
*/
|
|
||||||
private static final int DATA_GROUP = 2;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The index of the capturing group within SIGNED_COOKIE_FORMAT which
|
|
||||||
* contains the signature.
|
|
||||||
*/
|
|
||||||
private static final int SIGNATURE_GROUP = 3;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The signature algorithm that should be used to sign the cookie, as
|
|
||||||
* defined by:
|
|
||||||
* http://docs.oracle.com/javase/7/docs/technotes/guides/security/StandardNames.html#Mac
|
|
||||||
*/
|
|
||||||
private static final String SIGNATURE_ALGORITHM = "HmacSHA1";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of a signed Duo cookie. Each signed Duo cookie has an
|
|
||||||
* associated type which determines the prefix included in the string
|
|
||||||
* representation of that cookie. As that type is included in the data
|
|
||||||
* that is signed, different types will result in different signatures,
|
|
||||||
* even if the data portion of the cookie is otherwise identical.
|
|
||||||
*/
|
|
||||||
public enum Type {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Duo cookie which has been signed with the secret key for inclusion
|
|
||||||
* in a Duo request.
|
|
||||||
*/
|
|
||||||
DUO_REQUEST("TX"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Duo cookie which has been signed with the secret key by Duo and
|
|
||||||
* was included in a Duo response.
|
|
||||||
*/
|
|
||||||
DUO_RESPONSE("AUTH"),
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A Duo cookie which has been signed with the application key for
|
|
||||||
* inclusion in a Duo request. Such cookies are also included in Duo
|
|
||||||
* responses, for verification by the application.
|
|
||||||
*/
|
|
||||||
APPLICATION("APP");
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The prefix associated with the Duo cookie type. This prefix will
|
|
||||||
* be included in the string representation of the cookie.
|
|
||||||
*/
|
|
||||||
private final String prefix;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new Duo cookie type associated with the given string
|
|
||||||
* prefix. This prefix will be included in the string representation of
|
|
||||||
* the cookie.
|
|
||||||
*
|
|
||||||
* @param prefix
|
|
||||||
* The prefix to associated with the Duo cookie type.
|
|
||||||
*/
|
|
||||||
Type(String prefix) {
|
|
||||||
this.prefix = prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the prefix associated with the Duo cookie type.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The prefix to associated with this Duo cookie type.
|
|
||||||
*/
|
|
||||||
public String getPrefix() {
|
|
||||||
return prefix;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the cookie type associated with the given prefix. If no such
|
|
||||||
* cookie type exists, null is returned.
|
|
||||||
*
|
|
||||||
* @param prefix
|
|
||||||
* The prefix of the cookie type to search for.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The cookie type associated with the given prefix, or null if no
|
|
||||||
* such cookie type exists.
|
|
||||||
*/
|
|
||||||
public static Type fromPrefix(String prefix) {
|
|
||||||
|
|
||||||
// Search through all defined cookie types for the given prefix
|
|
||||||
for (Type type : Type.values()) {
|
|
||||||
if (type.getPrefix().equals(prefix))
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
// No such cookie type exists
|
|
||||||
return null;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The type of this Duo cookie.
|
|
||||||
*/
|
|
||||||
private final Type type;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The signature produced when the cookie was signed with HMAC-SHA1. The
|
|
||||||
* signature covers the prefix of the type and the cookie's base64-encoded
|
|
||||||
* data, separated by a pipe symbol.
|
|
||||||
*/
|
|
||||||
private final String signature;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new SignedDuoCookie which describes the identity of a user
|
|
||||||
* being verified and is cryptographically signed with HMAC-SHA1 by a given
|
|
||||||
* key.
|
|
||||||
*
|
|
||||||
* @param cookie
|
|
||||||
* The cookie defining the identity being verified.
|
|
||||||
*
|
|
||||||
* @param type
|
|
||||||
* The type of the cookie being created.
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* The key to use to generate the cryptographic signature. This key
|
|
||||||
* will not be stored within the cookie.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If the given signing key is invalid.
|
|
||||||
*/
|
|
||||||
public SignedDuoCookie(DuoCookie cookie, Type type, String key)
|
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
// Init underlying cookie
|
|
||||||
super(cookie.getUsername(), cookie.getIntegrationKey(),
|
|
||||||
cookie.getExpirationTimestamp());
|
|
||||||
|
|
||||||
// Store cookie type and signature
|
|
||||||
this.type = type;
|
|
||||||
this.signature = sign(key, type.getPrefix() + "|" + cookie.toString());
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Signs the given arbitrary string data with the given key using the
|
|
||||||
* algorithm defined by SIGNATURE_ALGORITHM. Both the data and the key will
|
|
||||||
* be interpreted as UTF-8 bytes.
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* The key which should be used to sign the given data.
|
|
||||||
*
|
|
||||||
* @param data
|
|
||||||
* The data being signed.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The signature produced by signing the given data with the given key,
|
|
||||||
* encoded as lowercase hexadecimal.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If the given signing key is invalid.
|
|
||||||
*/
|
|
||||||
private static String sign(String key, String data) throws GuacamoleException {
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
// Attempt to sign UTF-8 bytes of provided data
|
|
||||||
Mac mac = Mac.getInstance(SIGNATURE_ALGORITHM);
|
|
||||||
mac.init(new SecretKeySpec(key.getBytes("UTF-8"), SIGNATURE_ALGORITHM));
|
|
||||||
|
|
||||||
// Return signature as hex
|
|
||||||
return BaseEncoding.base16().lowerCase().encode(mac.doFinal(data.getBytes("UTF-8")));
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
// Re-throw any errors which prevent signature
|
|
||||||
catch (InvalidKeyException e){
|
|
||||||
throw new GuacamoleServerException("Signing key is invalid.", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Throw hard errors if standard pieces of Java are missing
|
|
||||||
catch (UnsupportedEncodingException e) {
|
|
||||||
throw new UnsupportedOperationException("Unexpected lack of UTF-8 support.", e);
|
|
||||||
}
|
|
||||||
catch (NoSuchAlgorithmException e) {
|
|
||||||
throw new UnsupportedOperationException("Unexpected lack of support "
|
|
||||||
+ "for required signature algorithm "
|
|
||||||
+ "\"" + SIGNATURE_ALGORITHM + "\".", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the type of this Duo cookie. The Duo cookie type is dictated
|
|
||||||
* by the context of the cookie's use, and is included with the cookie's
|
|
||||||
* underlying data when generating the signature.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The type of this Duo cookie.
|
|
||||||
*/
|
|
||||||
public Type getType() {
|
|
||||||
return type;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the signature produced when the cookie was signed with HMAC-SHA1.
|
|
||||||
* The signature covers the prefix of the cookie's type and the cookie's
|
|
||||||
* base64-encoded data, separated by a pipe symbol.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The signature produced when the cookie was signed with HMAC-SHA1.
|
|
||||||
*/
|
|
||||||
public String getSignature() {
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses a signed Duo cookie string, such as that produced by the
|
|
||||||
* toString() function or received from the Duo service, producing a new
|
|
||||||
* SignedDuoCookie object containing the associated cookie data and
|
|
||||||
* signature. If the given string is not a valid Duo cookie, or if the
|
|
||||||
* signature is incorrect, an exception is thrown. Note that the cookie may
|
|
||||||
* be expired, and must be checked for expiration prior to actual use.
|
|
||||||
*
|
|
||||||
* @param key
|
|
||||||
* The key that was used to sign the Duo cookie.
|
|
||||||
*
|
|
||||||
* @param str
|
|
||||||
* The Duo cookie string to parse.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* A new SignedDuoCookie object containing the same data and signature
|
|
||||||
* as the given Duo cookie string.
|
|
||||||
*
|
|
||||||
* @throws GuacamoleException
|
|
||||||
* If the given string is not a valid Duo cookie string, or if the
|
|
||||||
* signature of the cookie is invalid.
|
|
||||||
*/
|
|
||||||
public static SignedDuoCookie parseSignedDuoCookie(String key, String str)
|
|
||||||
throws GuacamoleException {
|
|
||||||
|
|
||||||
// Verify format of provided data
|
|
||||||
Matcher matcher = SIGNED_COOKIE_FORMAT.matcher(str);
|
|
||||||
if (!matcher.matches())
|
|
||||||
throw new GuacamoleClientException("Format of signed Duo cookie "
|
|
||||||
+ "is invalid.");
|
|
||||||
|
|
||||||
// Parse type from prefix
|
|
||||||
Type type = Type.fromPrefix(matcher.group(PREFIX_GROUP));
|
|
||||||
if (type == null)
|
|
||||||
throw new GuacamoleClientException("Invalid Duo cookie prefix.");
|
|
||||||
|
|
||||||
// Parse cookie from base64-encoded data
|
|
||||||
DuoCookie cookie = DuoCookie.parseDuoCookie(matcher.group(DATA_GROUP));
|
|
||||||
|
|
||||||
// Verify signature of cookie
|
|
||||||
SignedDuoCookie signedCookie = new SignedDuoCookie(cookie, type, key);
|
|
||||||
if (!signedCookie.getSignature().equals(matcher.group(SIGNATURE_GROUP)))
|
|
||||||
throw new GuacamoleClientException("Duo cookie has incorrect signature.");
|
|
||||||
|
|
||||||
// Cookie has valid signature and has parsed successfully
|
|
||||||
return signedCookie;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the string representation of this SignedDuoCookie. The format
|
|
||||||
* used is identical to that required by the Duo service: the type prefix,
|
|
||||||
* base64-encoded cookie data, and HMAC-SHA1 signature separated by pipe
|
|
||||||
* symbols ("|").
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The string representation of this SignedDuoCookie.
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return type.getPrefix() + "|" + super.toString() + "|" + signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -20,9 +20,12 @@
|
|||||||
package org.apache.guacamole.auth.duo.conf;
|
package org.apache.guacamole.auth.duo.conf;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
import java.net.URI;
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.environment.Environment;
|
import org.apache.guacamole.environment.Environment;
|
||||||
|
import org.apache.guacamole.properties.IntegerGuacamoleProperty;
|
||||||
import org.apache.guacamole.properties.StringGuacamoleProperty;
|
import org.apache.guacamole.properties.StringGuacamoleProperty;
|
||||||
|
import org.apache.guacamole.properties.URIGuacamoleProperty;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for retrieving configuration information regarding the Duo
|
* Service for retrieving configuration information regarding the Duo
|
||||||
@@ -52,15 +55,15 @@ public class ConfigurationService {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property within guacamole.properties which defines the integration
|
* The property within guacamole.properties which defines the client id
|
||||||
* key received from Duo for verifying Guacamole users. This value MUST be
|
* received from Duo for verifying Guacamole users. This value MUST be
|
||||||
* exactly 20 characters.
|
* exactly 20 characters.
|
||||||
*/
|
*/
|
||||||
private static final StringGuacamoleProperty DUO_INTEGRATION_KEY =
|
private static final StringGuacamoleProperty DUO_CLIENT_ID =
|
||||||
new StringGuacamoleProperty() {
|
new StringGuacamoleProperty() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return "duo-integration-key"; }
|
public String getName() { return "duo-client-id"; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -69,25 +72,37 @@ public class ConfigurationService {
|
|||||||
* received from Duo for verifying Guacamole users. This value MUST be
|
* received from Duo for verifying Guacamole users. This value MUST be
|
||||||
* exactly 40 characters.
|
* exactly 40 characters.
|
||||||
*/
|
*/
|
||||||
private static final StringGuacamoleProperty DUO_SECRET_KEY =
|
private static final StringGuacamoleProperty DUO_CLIENT_SECRET =
|
||||||
new StringGuacamoleProperty() {
|
new StringGuacamoleProperty() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return "duo-secret-key"; }
|
public String getName() { return "duo-client-secret"; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The property within guacamole.properties which defines the arbitrary
|
* The property within guacamole.properties which defines the redirect URI
|
||||||
* random key which was generated for Guacamole. Note that this value is not
|
* that Duo will call after the second factor has been completed. This
|
||||||
* provided by Duo, but is expected to be generated by the administrator of
|
* should be the URI used to access Guacamole.
|
||||||
* the system hosting Guacamole. This value MUST be at least 40 characters.
|
|
||||||
*/
|
*/
|
||||||
private static final StringGuacamoleProperty DUO_APPLICATION_KEY =
|
private static final URIGuacamoleProperty DUO_REDIRECT_URI =
|
||||||
new StringGuacamoleProperty() {
|
new URIGuacamoleProperty() {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() { return "duo-application-key"; }
|
public String getName() { return "duo-redirect-uri"; }
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The property that configures the timeout, in seconds, of in-progress
|
||||||
|
* Duo authentication attempts. Authentication attempts that take longer
|
||||||
|
* than this period of time will be invalidated.
|
||||||
|
*/
|
||||||
|
private static final IntegerGuacamoleProperty DUO_AUTH_TIMEOUT =
|
||||||
|
new IntegerGuacamoleProperty() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() { return "duo-auth-timeout"; }
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -110,51 +125,65 @@ public class ConfigurationService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the integration key received from Duo for verifying Guacamole
|
* Returns the Duo client id received from Duo for verifying Guacamole
|
||||||
* users, as defined in guacamole.properties by the "duo-integration-key"
|
* users, as defined in guacamole.properties by the "duo-client-id"
|
||||||
* property. This value MUST be exactly 20 characters.
|
* property. This value MUST be exactly 20 characters.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The integration key received from Duo for verifying Guacamole
|
* The client id received from Duo for verifying Guacamole users.
|
||||||
* users.
|
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If the associated property within guacamole.properties is missing.
|
* If the associated property within guacamole.properties is missing.
|
||||||
*/
|
*/
|
||||||
public String getIntegrationKey() throws GuacamoleException {
|
public String getClientId() throws GuacamoleException {
|
||||||
return environment.getRequiredProperty(DUO_INTEGRATION_KEY);
|
return environment.getRequiredProperty(DUO_CLIENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the secret key received from Duo for verifying Guacamole users,
|
* Returns the client secret received from Duo for verifying Guacamole users,
|
||||||
* as defined in guacamole.properties by the "duo-secret-key" property. This
|
* as defined in guacamole.properties by the "duo-client-secret" property.
|
||||||
* value MUST be exactly 20 characters.
|
* This value MUST be exactly 20 characters.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The secret key received from Duo for verifying Guacamole users.
|
* The client secret received from Duo for verifying Guacamole users.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If the associated property within guacamole.properties is missing.
|
* If the associated property within guacamole.properties is missing.
|
||||||
*/
|
*/
|
||||||
public String getSecretKey() throws GuacamoleException {
|
public String getClientSecret() throws GuacamoleException {
|
||||||
return environment.getRequiredProperty(DUO_SECRET_KEY);
|
return environment.getRequiredProperty(DUO_CLIENT_SECRET);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the arbitrary random key which was generated for Guacamole, as
|
* Return the callback URI that will be called by Duo after authentication
|
||||||
* defined in guacamole.properties by the "duo-application-key" property.
|
* with Duo has been completed. This should be the URI to return the user
|
||||||
* Note that this value is not provided by Duo, but is expected to be
|
* to the Guacamole interface, and will be a full URI.
|
||||||
* generated by the administrator of the system hosting Guacamole. This
|
|
||||||
* value MUST be at least 40 characters.
|
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* The arbitrary random key which was generated for Guacamole.
|
* The URL for Duo to use to callback to the Guacamole interface after
|
||||||
|
* authentication has been completed.
|
||||||
*
|
*
|
||||||
* @throws GuacamoleException
|
* @throws GuacamoleException
|
||||||
* If the associated property within guacamole.properties is missing.
|
* If guacamole.properties cannot be read, or if the property is not
|
||||||
|
* defined.
|
||||||
*/
|
*/
|
||||||
public String getApplicationKey() throws GuacamoleException {
|
public URI getRedirectUri() throws GuacamoleException {
|
||||||
return environment.getRequiredProperty(DUO_APPLICATION_KEY);
|
return environment.getRequiredProperty(DUO_REDIRECT_URI);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Return the number of seconds after which in-progress authentication attempts with
|
||||||
|
* Duo should be invalidated. The default is 30 seconds.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The number of seconds after which in-progress Duo MFA attempts should
|
||||||
|
* be invalidated.
|
||||||
|
*
|
||||||
|
* @throws GuacamoleException
|
||||||
|
* If guacamole.properties cannot be parsed.
|
||||||
|
*/
|
||||||
|
public int getAuthTimeout() throws GuacamoleException {
|
||||||
|
return environment.getProperty(DUO_AUTH_TIMEOUT, 30);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,98 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.apache.guacamole.auth.duo.form;
|
|
||||||
|
|
||||||
import org.apache.guacamole.form.Field;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A custom field type which uses the DuoWeb API to produce a signed response
|
|
||||||
* for a particular user. The signed response serves as an additional
|
|
||||||
* authentication factor, as it cryptographically verifies possession of the
|
|
||||||
* physical device associated with that user's Duo account.
|
|
||||||
*/
|
|
||||||
public class DuoSignedResponseField extends Field {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The name of the HTTP parameter which an instance of this field will
|
|
||||||
* populate within a user's credentials.
|
|
||||||
*/
|
|
||||||
public static final String PARAMETER_NAME = "guac-duo-signed-response";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The unique name associated with this field type.
|
|
||||||
*/
|
|
||||||
private static final String FIELD_TYPE_NAME = "GUAC_DUO_SIGNED_RESPONSE";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The hostname of the DuoWeb API endpoint.
|
|
||||||
*/
|
|
||||||
private final String apiHost;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The signed request generated by a call to DuoWeb.signRequest().
|
|
||||||
*/
|
|
||||||
private final String signedRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new field which uses the DuoWeb API to prompt the user for
|
|
||||||
* additional credentials. The provided credentials, if valid, will
|
|
||||||
* ultimately be verified by Duo's service, resulting in a signed response
|
|
||||||
* which can be cryptographically verified.
|
|
||||||
*
|
|
||||||
* @param apiHost
|
|
||||||
* The hostname of the DuoWeb API endpoint.
|
|
||||||
*
|
|
||||||
* @param signedRequest
|
|
||||||
* A signed request generated for the user in question by a call to
|
|
||||||
* DuoWeb.signRequest().
|
|
||||||
*/
|
|
||||||
public DuoSignedResponseField(String apiHost, String signedRequest) {
|
|
||||||
|
|
||||||
// Init base field type properties
|
|
||||||
super(PARAMETER_NAME, FIELD_TYPE_NAME);
|
|
||||||
|
|
||||||
// Init Duo-specific properties
|
|
||||||
this.apiHost = apiHost;
|
|
||||||
this.signedRequest = signedRequest;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the hostname of the DuoWeb API endpoint.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The hostname of the DuoWeb API endpoint.
|
|
||||||
*/
|
|
||||||
public String getApiHost() {
|
|
||||||
return apiHost;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the signed request string, which must have been generated by a
|
|
||||||
* call to DuoWeb.signRequest().
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* The signed request generated by a call to DuoWeb.signRequest().
|
|
||||||
*/
|
|
||||||
public String getSignedRequest() {
|
|
||||||
return signedRequest;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@@ -1,33 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Config block which registers Duo-specific field types.
|
|
||||||
*/
|
|
||||||
angular.module('guacDuo').config(['formServiceProvider',
|
|
||||||
function guacDuoConfig(formServiceProvider) {
|
|
||||||
|
|
||||||
// Define field for the signed response from the Duo service
|
|
||||||
formServiceProvider.registerFieldType('GUAC_DUO_SIGNED_RESPONSE', {
|
|
||||||
module : 'guacDuo',
|
|
||||||
controller : 'duoSignedResponseController',
|
|
||||||
templateUrl : 'app/ext/duo/templates/duoSignedResponseField.html'
|
|
||||||
});
|
|
||||||
|
|
||||||
}]);
|
|
@@ -1,86 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Controller for the "GUAC_DUO_SIGNED_RESPONSE" field which uses the DuoWeb
|
|
||||||
* API to prompt the user for additional credentials, ultimately receiving a
|
|
||||||
* signed response from the Duo service.
|
|
||||||
*/
|
|
||||||
angular.module('guacDuo').controller('duoSignedResponseController', ['$scope', '$element',
|
|
||||||
function duoSignedResponseController($scope, $element) {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The iframe which contains the Duo authentication interface.
|
|
||||||
*
|
|
||||||
* @type HTMLIFrameElement
|
|
||||||
*/
|
|
||||||
var iframe = $element.find('iframe')[0];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The submit button which should be used to submit the login form once
|
|
||||||
* the Duo response has been received.
|
|
||||||
*
|
|
||||||
* @type HTMLInputElement
|
|
||||||
*/
|
|
||||||
var submit = $element.find('input[type="submit"]')[0];
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the Duo interface has finished loading within the iframe.
|
|
||||||
*
|
|
||||||
* @type Boolean
|
|
||||||
*/
|
|
||||||
$scope.duoInterfaceLoaded = false;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Submits the signed response from Duo once the user has authenticated.
|
|
||||||
* This is a callback invoked by the DuoWeb API after the user has been
|
|
||||||
* verified and the signed response has been received.
|
|
||||||
*
|
|
||||||
* @param {HTMLFormElement} form
|
|
||||||
* The form element provided by the DuoWeb API containing the signed
|
|
||||||
* response as the value of an input field named "sig_response".
|
|
||||||
*/
|
|
||||||
var submitSignedResponse = function submitSignedResponse(form) {
|
|
||||||
|
|
||||||
// Update model to match received response
|
|
||||||
$scope.$apply(function updateModel() {
|
|
||||||
$scope.model = form.elements['sig_response'].value;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Submit updated credentials
|
|
||||||
submit.click();
|
|
||||||
|
|
||||||
};
|
|
||||||
|
|
||||||
// Update Duo loaded state when iframe finishes loading
|
|
||||||
iframe.onload = function duoLoaded() {
|
|
||||||
$scope.$apply(function updateLoadedState() {
|
|
||||||
$scope.duoInterfaceLoaded = true;
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Initialize Duo interface within iframe
|
|
||||||
Duo.init({
|
|
||||||
iframe : iframe,
|
|
||||||
host : $scope.field.apiHost,
|
|
||||||
sig_request : $scope.field.signedRequest,
|
|
||||||
submit_callback : submitSignedResponse
|
|
||||||
});
|
|
||||||
|
|
||||||
}]);
|
|
@@ -1,28 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Module which provides handling for Duo multi-factor authentication.
|
|
||||||
*/
|
|
||||||
angular.module('guacDuo', [
|
|
||||||
'form'
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Ensure the guacDuo module is loaded along with the rest of the app
|
|
||||||
angular.module('index').requires.push('guacDuo');
|
|
@@ -20,18 +20,6 @@
|
|||||||
"translations/pt.json",
|
"translations/pt.json",
|
||||||
"translations/ru.json",
|
"translations/ru.json",
|
||||||
"translations/zh.json"
|
"translations/zh.json"
|
||||||
],
|
]
|
||||||
|
|
||||||
"js" : [
|
|
||||||
"duo.min.js"
|
|
||||||
],
|
|
||||||
|
|
||||||
"css" : [
|
|
||||||
"duo.min.css"
|
|
||||||
],
|
|
||||||
|
|
||||||
"resources" : {
|
|
||||||
"templates/duoSignedResponseField.html" : "text/html"
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -1,366 +0,0 @@
|
|||||||
/**
|
|
||||||
* Duo Web SDK v2
|
|
||||||
* Copyright 2015, Duo Security
|
|
||||||
*/
|
|
||||||
window.Duo = (function(document, window) {
|
|
||||||
var DUO_MESSAGE_FORMAT = /^(?:AUTH|ENROLL)+\|[A-Za-z0-9\+\/=]+\|[A-Za-z0-9\+\/=]+$/;
|
|
||||||
var DUO_ERROR_FORMAT = /^ERR\|[\w\s\.\(\)]+$/;
|
|
||||||
|
|
||||||
var iframeId = 'duo_iframe',
|
|
||||||
postAction = '',
|
|
||||||
postArgument = 'sig_response',
|
|
||||||
host,
|
|
||||||
sigRequest,
|
|
||||||
duoSig,
|
|
||||||
appSig,
|
|
||||||
iframe,
|
|
||||||
submitCallback;
|
|
||||||
|
|
||||||
function throwError(message, url) {
|
|
||||||
throw new Error(
|
|
||||||
'Duo Web SDK error: ' + message +
|
|
||||||
(url ? ('\n' + 'See ' + url + ' for more information') : '')
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function hyphenize(str) {
|
|
||||||
return str.replace(/([a-z])([A-Z])/, '$1-$2').toLowerCase();
|
|
||||||
}
|
|
||||||
|
|
||||||
// cross-browser data attributes
|
|
||||||
function getDataAttribute(element, name) {
|
|
||||||
if ('dataset' in element) {
|
|
||||||
return element.dataset[name];
|
|
||||||
} else {
|
|
||||||
return element.getAttribute('data-' + hyphenize(name));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// cross-browser event binding/unbinding
|
|
||||||
function on(context, event, fallbackEvent, callback) {
|
|
||||||
if ('addEventListener' in window) {
|
|
||||||
context.addEventListener(event, callback, false);
|
|
||||||
} else {
|
|
||||||
context.attachEvent(fallbackEvent, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function off(context, event, fallbackEvent, callback) {
|
|
||||||
if ('removeEventListener' in window) {
|
|
||||||
context.removeEventListener(event, callback, false);
|
|
||||||
} else {
|
|
||||||
context.detachEvent(fallbackEvent, callback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function onReady(callback) {
|
|
||||||
on(document, 'DOMContentLoaded', 'onreadystatechange', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function offReady(callback) {
|
|
||||||
off(document, 'DOMContentLoaded', 'onreadystatechange', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function onMessage(callback) {
|
|
||||||
on(window, 'message', 'onmessage', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
function offMessage(callback) {
|
|
||||||
off(window, 'message', 'onmessage', callback);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parse the sig_request parameter, throwing errors if the token contains
|
|
||||||
* a server error or if the token is invalid.
|
|
||||||
*
|
|
||||||
* @param {String} sig Request token
|
|
||||||
*/
|
|
||||||
function parseSigRequest(sig) {
|
|
||||||
if (!sig) {
|
|
||||||
// nothing to do
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// see if the token contains an error, throwing it if it does
|
|
||||||
if (sig.indexOf('ERR|') === 0) {
|
|
||||||
throwError(sig.split('|')[1]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// validate the token
|
|
||||||
if (sig.indexOf(':') === -1 || sig.split(':').length !== 2) {
|
|
||||||
throwError(
|
|
||||||
'Duo was given a bad token. This might indicate a configuration ' +
|
|
||||||
'problem with one of Duo\'s client libraries.',
|
|
||||||
'https://www.duosecurity.com/docs/duoweb#first-steps'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
var sigParts = sig.split(':');
|
|
||||||
|
|
||||||
// hang on to the token, and the parsed duo and app sigs
|
|
||||||
sigRequest = sig;
|
|
||||||
duoSig = sigParts[0];
|
|
||||||
appSig = sigParts[1];
|
|
||||||
|
|
||||||
return {
|
|
||||||
sigRequest: sig,
|
|
||||||
duoSig: sigParts[0],
|
|
||||||
appSig: sigParts[1]
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is set up to run when the DOM is ready, if the iframe was
|
|
||||||
* not available during `init`.
|
|
||||||
*/
|
|
||||||
function onDOMReady() {
|
|
||||||
iframe = document.getElementById(iframeId);
|
|
||||||
|
|
||||||
if (!iframe) {
|
|
||||||
throw new Error(
|
|
||||||
'This page does not contain an iframe for Duo to use.' +
|
|
||||||
'Add an element like <iframe id="duo_iframe"></iframe> ' +
|
|
||||||
'to this page. ' +
|
|
||||||
'See https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe ' +
|
|
||||||
'for more information.'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
// we've got an iframe, away we go!
|
|
||||||
ready();
|
|
||||||
|
|
||||||
// always clean up after yourself
|
|
||||||
offReady(onDOMReady);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate that a MessageEvent came from the Duo service, and that it
|
|
||||||
* is a properly formatted payload.
|
|
||||||
*
|
|
||||||
* The Google Chrome sign-in page injects some JS into pages that also
|
|
||||||
* make use of postMessage, so we need to do additional validation above
|
|
||||||
* and beyond the origin.
|
|
||||||
*
|
|
||||||
* @param {MessageEvent} event Message received via postMessage
|
|
||||||
*/
|
|
||||||
function isDuoMessage(event) {
|
|
||||||
return Boolean(
|
|
||||||
event.origin === ('https://' + host) &&
|
|
||||||
typeof event.data === 'string' &&
|
|
||||||
(
|
|
||||||
event.data.match(DUO_MESSAGE_FORMAT) ||
|
|
||||||
event.data.match(DUO_ERROR_FORMAT)
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Validate the request token and prepare for the iframe to become ready.
|
|
||||||
*
|
|
||||||
* All options below can be passed into an options hash to `Duo.init`, or
|
|
||||||
* specified on the iframe using `data-` attributes.
|
|
||||||
*
|
|
||||||
* Options specified using the options hash will take precedence over
|
|
||||||
* `data-` attributes.
|
|
||||||
*
|
|
||||||
* Example using options hash:
|
|
||||||
* ```javascript
|
|
||||||
* Duo.init({
|
|
||||||
* iframe: "some_other_id",
|
|
||||||
* host: "api-main.duo.test",
|
|
||||||
* sig_request: "...",
|
|
||||||
* post_action: "/auth",
|
|
||||||
* post_argument: "resp"
|
|
||||||
* });
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* Example using `data-` attributes:
|
|
||||||
* ```
|
|
||||||
* <iframe id="duo_iframe"
|
|
||||||
* data-host="api-main.duo.test"
|
|
||||||
* data-sig-request="..."
|
|
||||||
* data-post-action="/auth"
|
|
||||||
* data-post-argument="resp"
|
|
||||||
* >
|
|
||||||
* </iframe>
|
|
||||||
* ```
|
|
||||||
*
|
|
||||||
* @param {Object} options
|
|
||||||
* @param {String} options.iframe The iframe, or id of an iframe to set up
|
|
||||||
* @param {String} options.host Hostname
|
|
||||||
* @param {String} options.sig_request Request token
|
|
||||||
* @param {String} [options.post_action=''] URL to POST back to after successful auth
|
|
||||||
* @param {String} [options.post_argument='sig_response'] Parameter name to use for response token
|
|
||||||
* @param {Function} [options.submit_callback] If provided, duo will not submit the form instead execute
|
|
||||||
* the callback function with reference to the "duo_form" form object
|
|
||||||
* submit_callback can be used to prevent the webpage from reloading.
|
|
||||||
*/
|
|
||||||
function init(options) {
|
|
||||||
if (options) {
|
|
||||||
if (options.host) {
|
|
||||||
host = options.host;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.sig_request) {
|
|
||||||
parseSigRequest(options.sig_request);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.post_action) {
|
|
||||||
postAction = options.post_action;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.post_argument) {
|
|
||||||
postArgument = options.post_argument;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (options.iframe) {
|
|
||||||
if ('tagName' in options.iframe) {
|
|
||||||
iframe = options.iframe;
|
|
||||||
} else if (typeof options.iframe === 'string') {
|
|
||||||
iframeId = options.iframe;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (typeof options.submit_callback === 'function') {
|
|
||||||
submitCallback = options.submit_callback;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if we were given an iframe, no need to wait for the rest of the DOM
|
|
||||||
if (iframe) {
|
|
||||||
ready();
|
|
||||||
} else {
|
|
||||||
// try to find the iframe in the DOM
|
|
||||||
iframe = document.getElementById(iframeId);
|
|
||||||
|
|
||||||
// iframe is in the DOM, away we go!
|
|
||||||
if (iframe) {
|
|
||||||
ready();
|
|
||||||
} else {
|
|
||||||
// wait until the DOM is ready, then try again
|
|
||||||
onReady(onDOMReady);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// always clean up after yourself!
|
|
||||||
offReady(init);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This function is called when a message was received from another domain
|
|
||||||
* using the `postMessage` API. Check that the event came from the Duo
|
|
||||||
* service domain, and that the message is a properly formatted payload,
|
|
||||||
* then perform the post back to the primary service.
|
|
||||||
*
|
|
||||||
* @param event Event object (contains origin and data)
|
|
||||||
*/
|
|
||||||
function onReceivedMessage(event) {
|
|
||||||
if (isDuoMessage(event)) {
|
|
||||||
// the event came from duo, do the post back
|
|
||||||
doPostBack(event.data);
|
|
||||||
|
|
||||||
// always clean up after yourself!
|
|
||||||
offMessage(onReceivedMessage);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Point the iframe at Duo, then wait for it to postMessage back to us.
|
|
||||||
*/
|
|
||||||
function ready() {
|
|
||||||
if (!host) {
|
|
||||||
host = getDataAttribute(iframe, 'host');
|
|
||||||
|
|
||||||
if (!host) {
|
|
||||||
throwError(
|
|
||||||
'No API hostname is given for Duo to use. Be sure to pass ' +
|
|
||||||
'a `host` parameter to Duo.init, or through the `data-host` ' +
|
|
||||||
'attribute on the iframe element.',
|
|
||||||
'https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!duoSig || !appSig) {
|
|
||||||
parseSigRequest(getDataAttribute(iframe, 'sigRequest'));
|
|
||||||
|
|
||||||
if (!duoSig || !appSig) {
|
|
||||||
throwError(
|
|
||||||
'No valid signed request is given. Be sure to give the ' +
|
|
||||||
'`sig_request` parameter to Duo.init, or use the ' +
|
|
||||||
'`data-sig-request` attribute on the iframe element.',
|
|
||||||
'https://www.duosecurity.com/docs/duoweb#3.-show-the-iframe'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// if postAction/Argument are defaults, see if they are specified
|
|
||||||
// as data attributes on the iframe
|
|
||||||
if (postAction === '') {
|
|
||||||
postAction = getDataAttribute(iframe, 'postAction') || postAction;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (postArgument === 'sig_response') {
|
|
||||||
postArgument = getDataAttribute(iframe, 'postArgument') || postArgument;
|
|
||||||
}
|
|
||||||
|
|
||||||
// point the iframe at Duo
|
|
||||||
iframe.src = [
|
|
||||||
'https://', host, '/frame/web/v1/auth?tx=', duoSig,
|
|
||||||
'&parent=', encodeURIComponent(document.location.href),
|
|
||||||
'&v=2.3'
|
|
||||||
].join('');
|
|
||||||
|
|
||||||
// listen for the 'message' event
|
|
||||||
onMessage(onReceivedMessage);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We received a postMessage from Duo. POST back to the primary service
|
|
||||||
* with the response token, and any additional user-supplied parameters
|
|
||||||
* given in form#duo_form.
|
|
||||||
*/
|
|
||||||
function doPostBack(response) {
|
|
||||||
// create a hidden input to contain the response token
|
|
||||||
var input = document.createElement('input');
|
|
||||||
input.type = 'hidden';
|
|
||||||
input.name = postArgument;
|
|
||||||
input.value = response + ':' + appSig;
|
|
||||||
|
|
||||||
// user may supply their own form with additional inputs
|
|
||||||
var form = document.getElementById('duo_form');
|
|
||||||
|
|
||||||
// if the form doesn't exist, create one
|
|
||||||
if (!form) {
|
|
||||||
form = document.createElement('form');
|
|
||||||
|
|
||||||
// insert the new form after the iframe
|
|
||||||
iframe.parentElement.insertBefore(form, iframe.nextSibling);
|
|
||||||
}
|
|
||||||
|
|
||||||
// make sure we are actually posting to the right place
|
|
||||||
form.method = 'POST';
|
|
||||||
form.action = postAction;
|
|
||||||
|
|
||||||
// add the response token input to the form
|
|
||||||
form.appendChild(input);
|
|
||||||
|
|
||||||
// away we go!
|
|
||||||
if (typeof submitCallback === "function") {
|
|
||||||
submitCallback.call(null, form);
|
|
||||||
} else {
|
|
||||||
form.submit();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// when the DOM is ready, initialize
|
|
||||||
// note that this will get cleaned up if the user calls init directly!
|
|
||||||
onReady(init);
|
|
||||||
|
|
||||||
return {
|
|
||||||
init: init,
|
|
||||||
_parseSigRequest: parseSigRequest,
|
|
||||||
_isDuoMessage: isDuoMessage,
|
|
||||||
_doPostBack: doPostBack
|
|
||||||
};
|
|
||||||
}(document, window));
|
|
@@ -1,27 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright (c) 2011, Duo Security, Inc.
|
|
||||||
* All rights reserved.
|
|
||||||
*
|
|
||||||
* Redistribution and use in source and binary forms, with or without
|
|
||||||
* modification, are permitted provided that the following conditions
|
|
||||||
* are met:
|
|
||||||
*
|
|
||||||
* 1. Redistributions of source code must retain the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer.
|
|
||||||
* 2. Redistributions in binary form must reproduce the above copyright
|
|
||||||
* notice, this list of conditions and the following disclaimer in the
|
|
||||||
* documentation and/or other materials provided with the distribution.
|
|
||||||
* 3. The name of the author may not be used to endorse or promote products
|
|
||||||
* derived from this software without specific prior written permission.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
|
|
||||||
*/
|
|
@@ -1,62 +0,0 @@
|
|||||||
/*
|
|
||||||
* Licensed to the Apache Software Foundation (ASF) under one
|
|
||||||
* or more contributor license agreements. See the NOTICE file
|
|
||||||
* distributed with this work for additional information
|
|
||||||
* regarding copyright ownership. The ASF licenses this file
|
|
||||||
* to you under the Apache License, Version 2.0 (the
|
|
||||||
* "License"); you may not use this file except in compliance
|
|
||||||
* with the License. You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing,
|
|
||||||
* software distributed under the License is distributed on an
|
|
||||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
||||||
* KIND, either express or implied. See the License for the
|
|
||||||
* specific language governing permissions and limitations
|
|
||||||
* under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
.duo-signature-response-field-container {
|
|
||||||
height: 100%;
|
|
||||||
width: 100%;
|
|
||||||
position: fixed;
|
|
||||||
left: 0;
|
|
||||||
top: 0;
|
|
||||||
display: table;
|
|
||||||
background: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duo-signature-response-field {
|
|
||||||
width: 100%;
|
|
||||||
display: table-cell;
|
|
||||||
vertical-align: middle;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duo-signature-response-field input[type="submit"] {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duo-signature-response-field iframe {
|
|
||||||
width: 100%;
|
|
||||||
max-width: 620px;
|
|
||||||
height: 330px;
|
|
||||||
border: none;
|
|
||||||
box-shadow: 4px 4px 8px rgba(0, 0, 0, 0.5);
|
|
||||||
display: block;
|
|
||||||
margin: 1.5em auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duo-signature-response-field iframe {
|
|
||||||
opacity: 1;
|
|
||||||
-webkit-transition: opacity 0.125s;
|
|
||||||
-moz-transition: opacity 0.125s;
|
|
||||||
-ms-transition: opacity 0.125s;
|
|
||||||
-o-transition: opacity 0.125s;
|
|
||||||
transition: opacity 0.125s;
|
|
||||||
}
|
|
||||||
|
|
||||||
.duo-signature-response-field.loading iframe {
|
|
||||||
opacity: 0;
|
|
||||||
}
|
|
@@ -1,6 +0,0 @@
|
|||||||
<div class="duo-signature-response-field-container">
|
|
||||||
<div class="duo-signature-response-field" ng-class="{ loading : !duoInterfaceLoaded }">
|
|
||||||
<iframe></iframe>
|
|
||||||
<input type="submit">
|
|
||||||
</div>
|
|
||||||
</div>
|
|
@@ -7,7 +7,8 @@
|
|||||||
"LOGIN" : {
|
"LOGIN" : {
|
||||||
"FIELD_HEADER_GUAC_DUO_SIGNED_RESPONSE" : "",
|
"FIELD_HEADER_GUAC_DUO_SIGNED_RESPONSE" : "",
|
||||||
"INFO_DUO_VALIDATION_CODE_INCORRECT" : "Duo validation code incorrect.",
|
"INFO_DUO_VALIDATION_CODE_INCORRECT" : "Duo validation code incorrect.",
|
||||||
"INFO_DUO_AUTH_REQUIRED" : "Please authenticate with Duo to continue."
|
"INFO_DUO_AUTH_REQUIRED" : "Please authenticate with Duo to continue.",
|
||||||
|
"INFO_DUO_REDIRECT_PENDING" : "Please wait, redirecting to Duo..."
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -2,7 +2,8 @@
|
|||||||
|
|
||||||
"LOGIN" : {
|
"LOGIN" : {
|
||||||
"INFO_DUO_VALIDATION_CODE_INCORRECT" : "Duoの認証コードが間違っています。",
|
"INFO_DUO_VALIDATION_CODE_INCORRECT" : "Duoの認証コードが間違っています。",
|
||||||
"INFO_DUO_AUTH_REQUIRED" : "Duoで認証してください。"
|
"INFO_DUO_AUTH_REQUIRED" : "Duoで認証してください。",
|
||||||
|
"INFO_DUO_REDIRECT_PENDING" : "Duoへリダイレクトしています。"
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -19,11 +19,11 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.sso;
|
package org.apache.guacamole.auth.sso;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import org.apache.guacamole.net.auth.IdentifierGenerator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Service for generating and validating single-use random tokens (nonces).
|
* Service for generating and validating single-use random tokens (nonces).
|
||||||
@@ -31,12 +31,6 @@ import java.util.concurrent.ConcurrentHashMap;
|
|||||||
*/
|
*/
|
||||||
public class NonceService {
|
public class NonceService {
|
||||||
|
|
||||||
/**
|
|
||||||
* Generator of arbitrary, unique, unpredictable identifiers.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private IdentifierGenerator idGenerator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of all generated nonces to their corresponding expiration timestamps.
|
* Map of all generated nonces to their corresponding expiration timestamps.
|
||||||
* This Map must be periodically swept of expired nonces to avoid growing
|
* This Map must be periodically swept of expired nonces to avoid growing
|
||||||
@@ -107,7 +101,7 @@ public class NonceService {
|
|||||||
sweepExpiredNonces();
|
sweepExpiredNonces();
|
||||||
|
|
||||||
// Generate and store nonce, along with expiration timestamp
|
// Generate and store nonce, along with expiration timestamp
|
||||||
String nonce = idGenerator.generateIdentifier(NONCE_BITS, false);
|
String nonce = IdentifierGenerator.generateIdentifier(NONCE_BITS, false);
|
||||||
nonces.put(nonce, System.currentTimeMillis() + maxAge);
|
nonces.put(nonce, System.currentTimeMillis() + maxAge);
|
||||||
return nonce;
|
return nonce;
|
||||||
|
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.saml.acs;
|
package org.apache.guacamole.auth.saml.acs;
|
||||||
|
|
||||||
import org.apache.guacamole.auth.sso.AuthenticationSession;
|
import org.apache.guacamole.net.auth.AuthenticationSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of an in-progress SAML authentication attempt.
|
* Representation of an in-progress SAML authentication attempt.
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
package org.apache.guacamole.auth.saml.acs;
|
package org.apache.guacamole.auth.saml.acs;
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import org.apache.guacamole.auth.sso.AuthenticationSessionManager;
|
import org.apache.guacamole.net.auth.AuthenticationSessionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager service that temporarily stores SAML authentication attempts while
|
* Manager service that temporarily stores SAML authentication attempts while
|
||||||
|
@@ -36,7 +36,7 @@ import org.apache.guacamole.GuacamoleException;
|
|||||||
import org.apache.guacamole.GuacamoleSecurityException;
|
import org.apache.guacamole.GuacamoleSecurityException;
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
import org.apache.guacamole.GuacamoleServerException;
|
||||||
import org.apache.guacamole.auth.saml.conf.ConfigurationService;
|
import org.apache.guacamole.auth.saml.conf.ConfigurationService;
|
||||||
import org.apache.guacamole.auth.sso.IdentifierGenerator;
|
import org.apache.guacamole.net.auth.IdentifierGenerator;
|
||||||
import org.xml.sax.SAXException;
|
import org.xml.sax.SAXException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,12 +58,6 @@ public class SAMLService {
|
|||||||
@Inject
|
@Inject
|
||||||
private SAMLAuthenticationSessionManager sessionManager;
|
private SAMLAuthenticationSessionManager sessionManager;
|
||||||
|
|
||||||
/**
|
|
||||||
* Generator of arbitrary, unique, unpredictable identifiers.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private IdentifierGenerator idGenerator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new SAML request, beginning the overall authentication flow
|
* Creates a new SAML request, beginning the overall authentication flow
|
||||||
* that will ultimately result in an asserted user identity if the user is
|
* that will ultimately result in an asserted user identity if the user is
|
||||||
@@ -89,7 +83,7 @@ public class SAMLService {
|
|||||||
Auth auth = new Auth(samlSettings, null, null);
|
Auth auth = new Auth(samlSettings, null, null);
|
||||||
|
|
||||||
// Generate a unique ID to use for the relay state
|
// Generate a unique ID to use for the relay state
|
||||||
String identifier = idGenerator.generateIdentifier();
|
String identifier = IdentifierGenerator.generateIdentifier();
|
||||||
|
|
||||||
// Create the request URL for the SAML IdP
|
// Create the request URL for the SAML IdP
|
||||||
String requestUrl = auth.login(
|
String requestUrl = auth.login(
|
||||||
|
@@ -24,7 +24,6 @@ import com.onelogin.saml2.settings.IdPMetadataParser;
|
|||||||
import com.onelogin.saml2.settings.Saml2Settings;
|
import com.onelogin.saml2.settings.Saml2Settings;
|
||||||
import com.onelogin.saml2.settings.SettingsBuilder;
|
import com.onelogin.saml2.settings.SettingsBuilder;
|
||||||
import com.onelogin.saml2.util.Constants;
|
import com.onelogin.saml2.util.Constants;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
|
@@ -20,14 +20,8 @@
|
|||||||
package org.apache.guacamole.auth.ssl;
|
package org.apache.guacamole.auth.ssl;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
import com.google.inject.Singleton;
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
|
||||||
import org.apache.guacamole.auth.ssl.SSLAuthenticationSessionManager;
|
|
||||||
import org.apache.guacamole.auth.sso.SSOAuthenticationEventListener;
|
import org.apache.guacamole.auth.sso.SSOAuthenticationEventListener;
|
||||||
import org.apache.guacamole.net.auth.Credentials;
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
import org.apache.guacamole.net.event.AuthenticationFailureEvent;
|
|
||||||
import org.apache.guacamole.net.event.AuthenticationSuccessEvent;
|
|
||||||
import org.apache.guacamole.net.event.listener.Listener;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A Listener that will reactivate or invalidate SSL auth sessions depending on
|
* A Listener that will reactivate or invalidate SSL auth sessions depending on
|
||||||
|
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
package org.apache.guacamole.auth.ssl;
|
package org.apache.guacamole.auth.ssl;
|
||||||
|
|
||||||
import org.apache.guacamole.auth.sso.AuthenticationSession;
|
import org.apache.guacamole.net.auth.AuthenticationSession;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of an in-progress SSL/TLS authentication attempt.
|
* Representation of an in-progress SSL/TLS authentication attempt.
|
||||||
|
@@ -20,7 +20,7 @@
|
|||||||
package org.apache.guacamole.auth.ssl;
|
package org.apache.guacamole.auth.ssl;
|
||||||
|
|
||||||
import com.google.inject.Singleton;
|
import com.google.inject.Singleton;
|
||||||
import org.apache.guacamole.auth.sso.AuthenticationSessionManager;
|
import org.apache.guacamole.net.auth.AuthenticationSessionManager;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Manager service that temporarily stores SSL/TLS authentication attempts
|
* Manager service that temporarily stores SSL/TLS authentication attempts
|
||||||
|
@@ -845,14 +845,13 @@ associate_totp() {
|
|||||||
|
|
||||||
##
|
##
|
||||||
## Adds properties to guacamole.properties which configure the Duo two-factor
|
## Adds properties to guacamole.properties which configure the Duo two-factor
|
||||||
## authentication service. Checks to see if all variables are defined and makes sure
|
## authentication service. Checks to see if all variables are defined
|
||||||
## DUO_APPLICATION_KEY is >= 40 characters.
|
|
||||||
##
|
##
|
||||||
associate_duo() {
|
associate_duo() {
|
||||||
# Verify required parameters are present
|
# Verify required parameters are present
|
||||||
if [ -z "$DUO_INTEGRATION_KEY" ] || \
|
if [ -z "$DUO_CLIENT_ID" ] || \
|
||||||
[ -z "$DUO_SECRET_KEY" ] || \
|
[ -z "$DUO_CLIENT_SECRET" ] || \
|
||||||
[ ${#DUO_APPLICATION_KEY} -lt 40 ]
|
[ -z "$DUO_REDIRECT_URI" ]
|
||||||
then
|
then
|
||||||
cat <<END
|
cat <<END
|
||||||
FATAL: Missing required environment variables
|
FATAL: Missing required environment variables
|
||||||
@@ -862,21 +861,20 @@ following environment variables:
|
|||||||
|
|
||||||
DUO_API_HOSTNAME The hostname of the Duo API endpoint.
|
DUO_API_HOSTNAME The hostname of the Duo API endpoint.
|
||||||
|
|
||||||
DUO_INTEGRATION_KEY The integration key provided for Guacamole by Duo.
|
DUO_CLIENT_ID The client id (or integration key) provided for Guacamole by Duo.
|
||||||
|
|
||||||
DUO_SECRET_KEY The secret key provided for Guacamole by Duo.
|
DUO_CLIENT_SECRET The secret key provided for Guacamole by Duo.
|
||||||
|
|
||||||
DUO_APPLICATION_KEY An arbitrary, random key.
|
DUO_REDIRECT_URI The URI to redirect back to upon successful authentication.
|
||||||
This value must be at least 40 characters.
|
|
||||||
END
|
END
|
||||||
exit 1;
|
exit 1;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Update config file
|
# Update config file
|
||||||
set_property "duo-api-hostname" "$DUO_API_HOSTNAME"
|
set_property "duo-api-hostname" "$DUO_API_HOSTNAME"
|
||||||
set_property "duo-integration-key" "$DUO_INTEGRATION_KEY"
|
set_property "duo-client-id" "$DUO_CLIENT_ID"
|
||||||
set_property "duo-secret-key" "$DUO_SECRET_KEY"
|
set_property "duo-client-secret" "$DUO_CLIENT_SECRET"
|
||||||
set_property "duo-application-key" "$DUO_APPLICATION_KEY"
|
set_property "duo-redirect-uri" "$DUO_REDIRECT_URI"
|
||||||
|
|
||||||
# Add required .jar files to GUACAMOLE_EXT
|
# Add required .jar files to GUACAMOLE_EXT
|
||||||
ln -s /opt/guacamole/duo/guacamole-auth-*.jar "$GUACAMOLE_EXT"
|
ln -s /opt/guacamole/duo/guacamole-auth-*.jar "$GUACAMOLE_EXT"
|
||||||
|
@@ -136,6 +136,46 @@ public class TranslatableGuacamoleInsufficientCredentialsException
|
|||||||
this(message, new TranslatableMessage(key), credentialsInfo);
|
this(message, new TranslatableMessage(key), credentialsInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new TranslatableGuacamoleInsufficientCredentialsException with the specified message,
|
||||||
|
* translation key, the credential information required for authentication, the state token, and
|
||||||
|
* an expiration timestamp for the state token. The message is provided in both a non-translatable
|
||||||
|
* form and as a translatable key which can be used to retrieve the localized message.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* A human-readable description of the exception that occurred. This
|
||||||
|
* message should be readable on its own and as-written, without
|
||||||
|
* requiring a translation service.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* The arbitrary key which can be used to look up the message to be
|
||||||
|
* displayed in the user's native language.
|
||||||
|
*
|
||||||
|
* @param credentialsInfo
|
||||||
|
* Information describing the form of valid credentials.
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* An opaque value that may be used by a client to maintain state across requests which are part
|
||||||
|
* of the same authentication transaction.
|
||||||
|
*
|
||||||
|
* @param providerIdentifier
|
||||||
|
* The identifier of the authentication provider that this exception pertains to.
|
||||||
|
*
|
||||||
|
* @param queryIdentifier
|
||||||
|
* The identifier of the specific query parameter within the
|
||||||
|
* authentication process that this exception pertains to.
|
||||||
|
*
|
||||||
|
* @param expires
|
||||||
|
* The timestamp after which the state token associated with the authentication process expires,
|
||||||
|
* specified as the number of milliseconds since the UNIX epoch.
|
||||||
|
*/
|
||||||
|
public TranslatableGuacamoleInsufficientCredentialsException(String message,
|
||||||
|
String key, CredentialsInfo credentialsInfo, String state, String providerIdentifier,
|
||||||
|
String queryIdentifier, long expires) {
|
||||||
|
super(message, credentialsInfo, state, providerIdentifier, queryIdentifier, expires);
|
||||||
|
this.translatableMessage = new TranslatableMessage(key);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TranslatableMessage getTranslatableMessage() {
|
public TranslatableMessage getTranslatableMessage() {
|
||||||
return translatableMessage;
|
return translatableMessage;
|
||||||
|
@@ -17,7 +17,7 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.auth.sso;
|
package org.apache.guacamole.net.auth;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Representation of an in-progress authentication attempt.
|
* Representation of an in-progress authentication attempt.
|
@@ -17,10 +17,7 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.auth.sso;
|
package org.apache.guacamole.net.auth;
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
|
||||||
import com.google.inject.Singleton;
|
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
@@ -39,14 +36,7 @@ import java.util.concurrent.TimeUnit;
|
|||||||
* @param <T>
|
* @param <T>
|
||||||
* The type of sessions managed by this session manager.
|
* The type of sessions managed by this session manager.
|
||||||
*/
|
*/
|
||||||
@Singleton
|
public abstract class AuthenticationSessionManager<T extends AuthenticationSession> {
|
||||||
public class AuthenticationSessionManager<T extends AuthenticationSession> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Generator of arbitrary, unique, unpredictable identifiers.
|
|
||||||
*/
|
|
||||||
@Inject
|
|
||||||
private IdentifierGenerator idGenerator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map of authentication session identifiers to their associated
|
* Map of authentication session identifiers to their associated
|
||||||
@@ -98,7 +88,7 @@ public class AuthenticationSessionManager<T extends AuthenticationSession> {
|
|||||||
* token.
|
* token.
|
||||||
*/
|
*/
|
||||||
public String generateInvalid() {
|
public String generateInvalid() {
|
||||||
return idGenerator.generateIdentifier();
|
return IdentifierGenerator.generateIdentifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -193,7 +183,7 @@ public class AuthenticationSessionManager<T extends AuthenticationSession> {
|
|||||||
* given session when calling resume().
|
* given session when calling resume().
|
||||||
*/
|
*/
|
||||||
public String defer(T session) {
|
public String defer(T session) {
|
||||||
String identifier = idGenerator.generateIdentifier();
|
String identifier = IdentifierGenerator.generateIdentifier();
|
||||||
sessions.put(identifier, session);
|
sessions.put(identifier, session);
|
||||||
return identifier;
|
return identifier;
|
||||||
}
|
}
|
@@ -34,6 +34,16 @@ import javax.servlet.http.HttpSession;
|
|||||||
*/
|
*/
|
||||||
public class Credentials implements Serializable {
|
public class Credentials implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The RESUME_QUERY is a query parameter key used to determine which
|
||||||
|
* authentication provider's process should be resumed during multi-step
|
||||||
|
* authentication. The auth provider will set this parameter before
|
||||||
|
* redirecting to an external service, and it is checked upon return to
|
||||||
|
* Guacamole to ensure the correct authentication state is continued
|
||||||
|
* without starting over.
|
||||||
|
*/
|
||||||
|
public static final String RESUME_QUERY = "provider_id";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Unique identifier associated with this specific version of Credentials.
|
* Unique identifier associated with this specific version of Credentials.
|
||||||
*/
|
*/
|
||||||
|
@@ -17,10 +17,9 @@
|
|||||||
* under the License.
|
* under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.apache.guacamole.auth.sso;
|
package org.apache.guacamole.net.auth;
|
||||||
|
|
||||||
import com.google.common.io.BaseEncoding;
|
import com.google.common.io.BaseEncoding;
|
||||||
import com.google.inject.Singleton;
|
|
||||||
import java.math.BigInteger;
|
import java.math.BigInteger;
|
||||||
import java.security.SecureRandom;
|
import java.security.SecureRandom;
|
||||||
|
|
||||||
@@ -29,14 +28,13 @@ import java.security.SecureRandom;
|
|||||||
* is an arbitrary, random string produced using a cryptographically-secure
|
* is an arbitrary, random string produced using a cryptographically-secure
|
||||||
* random number generator.
|
* random number generator.
|
||||||
*/
|
*/
|
||||||
@Singleton
|
|
||||||
public class IdentifierGenerator {
|
public class IdentifierGenerator {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cryptographically-secure random number generator for generating unique
|
* Cryptographically-secure random number generator for generating unique
|
||||||
* identifiers.
|
* identifiers.
|
||||||
*/
|
*/
|
||||||
private final SecureRandom secureRandom = new SecureRandom();
|
private static final SecureRandom secureRandom = new SecureRandom();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generates a unique and unpredictable identifier. Each identifier is at
|
* Generates a unique and unpredictable identifier. Each identifier is at
|
||||||
@@ -48,7 +46,7 @@ public class IdentifierGenerator {
|
|||||||
* A unique and unpredictable identifier with at least 256 bits of
|
* A unique and unpredictable identifier with at least 256 bits of
|
||||||
* entropy.
|
* entropy.
|
||||||
*/
|
*/
|
||||||
public String generateIdentifier() {
|
public static String generateIdentifier() {
|
||||||
return generateIdentifier(256);
|
return generateIdentifier(256);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +63,7 @@ public class IdentifierGenerator {
|
|||||||
* A unique and unpredictable identifier with at least the given number
|
* A unique and unpredictable identifier with at least the given number
|
||||||
* of bits of entropy.
|
* of bits of entropy.
|
||||||
*/
|
*/
|
||||||
public String generateIdentifier(int minBits) {
|
public static String generateIdentifier(int minBits) {
|
||||||
return generateIdentifier(minBits, true);
|
return generateIdentifier(minBits, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +85,7 @@ public class IdentifierGenerator {
|
|||||||
* A unique and unpredictable identifier with at least the given number
|
* A unique and unpredictable identifier with at least the given number
|
||||||
* of bits of entropy.
|
* of bits of entropy.
|
||||||
*/
|
*/
|
||||||
public String generateIdentifier(int minBits, boolean caseSensitive) {
|
public static String generateIdentifier(int minBits, boolean caseSensitive) {
|
||||||
|
|
||||||
// Generate a base64 identifier if we're allowed to vary by case
|
// Generate a base64 identifier if we're allowed to vary by case
|
||||||
if (caseSensitive) {
|
if (caseSensitive) {
|
@@ -28,6 +28,95 @@ package org.apache.guacamole.net.auth.credentials;
|
|||||||
*/
|
*/
|
||||||
public class GuacamoleInsufficientCredentialsException extends GuacamoleCredentialsException {
|
public class GuacamoleInsufficientCredentialsException extends GuacamoleCredentialsException {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default state token to use when no specific state information is provided.
|
||||||
|
*/
|
||||||
|
private static final String DEFAULT_STATE = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default provider identifier to use when no specific provider is identified.
|
||||||
|
* This serves as a placeholder indicating that either no specific provider is
|
||||||
|
* responsible for the exception or the responsible provider has not been identified.
|
||||||
|
*/
|
||||||
|
private static final String DEFAULT_PROVIDER_IDENTIFIER = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default query identifier to use when no specific query is identified.
|
||||||
|
* This serves as a placeholder and indicates that the specific query related to
|
||||||
|
* the provider's state resume operation has not been provided.
|
||||||
|
*/
|
||||||
|
private static final String DEFAULT_QUERY_IDENTIFIER = "";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The default expiration timestamp to use when no specific expiration is provided,
|
||||||
|
* effectively indicating that the state token does not expire.
|
||||||
|
*/
|
||||||
|
private static final long DEFAULT_EXPIRES = -1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An opaque value that may be used by a client to maintain state across requests
|
||||||
|
* which are part of the same authentication transaction.
|
||||||
|
*/
|
||||||
|
protected final String state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier for the authentication provider that threw this exception.
|
||||||
|
* This is used to link the exception back to the originating source of the
|
||||||
|
* authentication attempt, allowing clients to determine which provider's
|
||||||
|
* authentication process should be resumed.
|
||||||
|
*/
|
||||||
|
protected final String providerIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An identifier for the specific query within the URL for this provider that can
|
||||||
|
* be checked to resume the authentication state.
|
||||||
|
*/
|
||||||
|
protected final String queryIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp after which the state token associated with the authentication process
|
||||||
|
* should no longer be considered valid, expressed as the number of milliseconds since
|
||||||
|
* UNIX epoch.
|
||||||
|
*/
|
||||||
|
protected final long expires;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new GuacamoleInsufficientCredentialsException with the specified
|
||||||
|
* message, the credential information required for authentication, the state
|
||||||
|
* token associated with the authentication process, and an expiration timestamp.
|
||||||
|
*
|
||||||
|
* @param message
|
||||||
|
* A human-readable description of the exception that occurred.
|
||||||
|
*
|
||||||
|
* @param credentialsInfo
|
||||||
|
* Information describing the form of valid credentials.
|
||||||
|
*
|
||||||
|
* @param state
|
||||||
|
* An opaque value that may be used by a client to maintain state
|
||||||
|
* across requests which are part of the same authentication transaction.
|
||||||
|
*
|
||||||
|
* @param providerIdentifier
|
||||||
|
* The identifier of the authentication provider that this exception pertains to.
|
||||||
|
*
|
||||||
|
* @param queryIdentifier
|
||||||
|
* The identifier of the specific query parameter within the
|
||||||
|
* authentication process that this exception pertains to.
|
||||||
|
*
|
||||||
|
* @param expires
|
||||||
|
* The timestamp after which the state token associated with the
|
||||||
|
* authentication process should no longer be considered valid, expressed
|
||||||
|
* as the number of milliseconds since UNIX epoch.
|
||||||
|
*/
|
||||||
|
public GuacamoleInsufficientCredentialsException(String message,
|
||||||
|
CredentialsInfo credentialsInfo, String state,
|
||||||
|
String providerIdentifier, String queryIdentifier, long expires) {
|
||||||
|
super(message, credentialsInfo);
|
||||||
|
this.state = state;
|
||||||
|
this.providerIdentifier = providerIdentifier;
|
||||||
|
this.queryIdentifier = queryIdentifier;
|
||||||
|
this.expires = expires;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new GuacamoleInsufficientCredentialsException with the given
|
* Creates a new GuacamoleInsufficientCredentialsException with the given
|
||||||
* message, cause, and associated credential information.
|
* message, cause, and associated credential information.
|
||||||
@@ -44,6 +133,10 @@ public class GuacamoleInsufficientCredentialsException extends GuacamoleCredenti
|
|||||||
public GuacamoleInsufficientCredentialsException(String message, Throwable cause,
|
public GuacamoleInsufficientCredentialsException(String message, Throwable cause,
|
||||||
CredentialsInfo credentialsInfo) {
|
CredentialsInfo credentialsInfo) {
|
||||||
super(message, cause, credentialsInfo);
|
super(message, cause, credentialsInfo);
|
||||||
|
this.state = DEFAULT_STATE;
|
||||||
|
this.providerIdentifier = DEFAULT_PROVIDER_IDENTIFIER;
|
||||||
|
this.queryIdentifier = DEFAULT_QUERY_IDENTIFIER;
|
||||||
|
this.expires = DEFAULT_EXPIRES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -58,6 +151,10 @@ public class GuacamoleInsufficientCredentialsException extends GuacamoleCredenti
|
|||||||
*/
|
*/
|
||||||
public GuacamoleInsufficientCredentialsException(String message, CredentialsInfo credentialsInfo) {
|
public GuacamoleInsufficientCredentialsException(String message, CredentialsInfo credentialsInfo) {
|
||||||
super(message, credentialsInfo);
|
super(message, credentialsInfo);
|
||||||
|
this.state = DEFAULT_STATE;
|
||||||
|
this.providerIdentifier = DEFAULT_PROVIDER_IDENTIFIER;
|
||||||
|
this.queryIdentifier = DEFAULT_QUERY_IDENTIFIER;
|
||||||
|
this.expires = DEFAULT_EXPIRES;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -72,6 +169,52 @@ public class GuacamoleInsufficientCredentialsException extends GuacamoleCredenti
|
|||||||
*/
|
*/
|
||||||
public GuacamoleInsufficientCredentialsException(Throwable cause, CredentialsInfo credentialsInfo) {
|
public GuacamoleInsufficientCredentialsException(Throwable cause, CredentialsInfo credentialsInfo) {
|
||||||
super(cause, credentialsInfo);
|
super(cause, credentialsInfo);
|
||||||
|
this.state = DEFAULT_STATE;
|
||||||
|
this.providerIdentifier = DEFAULT_PROVIDER_IDENTIFIER;
|
||||||
|
this.queryIdentifier = DEFAULT_QUERY_IDENTIFIER;
|
||||||
|
this.expires = DEFAULT_EXPIRES;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the state token associated with the authentication process.
|
||||||
|
*
|
||||||
|
* @return The opaque state token used to maintain consistency across multiple
|
||||||
|
* requests in the same authentication transaction.
|
||||||
|
*/
|
||||||
|
public String getState() {
|
||||||
|
return state;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the identifier of the authentication provider responsible for this exception.
|
||||||
|
*
|
||||||
|
* @return The identifier of the authentication provider, allowing clients to know
|
||||||
|
* which provider's process should be resumed in response to this exception.
|
||||||
|
*/
|
||||||
|
public String getProviderIdentifier() {
|
||||||
|
return providerIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the specific query identifier associated with the URL for the provider
|
||||||
|
* that can be checked to resume the authentication state.
|
||||||
|
*
|
||||||
|
* @return The query identifier that serves as a reference to a specific point or
|
||||||
|
* transaction within the provider's authentication process.
|
||||||
|
*/
|
||||||
|
public String getQueryIdentifier() {
|
||||||
|
return queryIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the expiration timestamp of the state token, specified as the
|
||||||
|
* number of milliseconds since the UNIX epoch.
|
||||||
|
*
|
||||||
|
* @return The expiration timestamp of the state token, or a negative value if
|
||||||
|
* the token does not expire.
|
||||||
|
*/
|
||||||
|
public long getExpires() {
|
||||||
|
return expires;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@@ -21,11 +21,14 @@ package org.apache.guacamole.rest.auth;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
|
||||||
import org.apache.guacamole.GuacamoleException;
|
import org.apache.guacamole.GuacamoleException;
|
||||||
import org.apache.guacamole.GuacamoleSecurityException;
|
import org.apache.guacamole.GuacamoleSecurityException;
|
||||||
import org.apache.guacamole.GuacamoleServerException;
|
|
||||||
import org.apache.guacamole.GuacamoleUnauthorizedException;
|
import org.apache.guacamole.GuacamoleUnauthorizedException;
|
||||||
import org.apache.guacamole.GuacamoleSession;
|
import org.apache.guacamole.GuacamoleSession;
|
||||||
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
import org.apache.guacamole.net.auth.AuthenticatedUser;
|
||||||
@@ -43,9 +46,13 @@ import org.glassfish.jersey.server.ContainerRequest;
|
|||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
|
import com.google.inject.Singleton;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A service for performing authentication checks in REST endpoints.
|
* A service for performing authentication checks in REST endpoints.
|
||||||
*/
|
*/
|
||||||
|
@Singleton
|
||||||
public class AuthenticationService {
|
public class AuthenticationService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -96,6 +103,11 @@ public class AuthenticationService {
|
|||||||
*/
|
*/
|
||||||
public static final String TOKEN_PARAMETER_NAME = "token";
|
public static final String TOKEN_PARAMETER_NAME = "token";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Map to store resumable authentication states with an expiration time.
|
||||||
|
*/
|
||||||
|
private Map<String, ResumableAuthenticationState> resumableStateMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Attempts authentication against all AuthenticationProviders, in order,
|
* Attempts authentication against all AuthenticationProviders, in order,
|
||||||
* using the provided credentials. The first authentication failure takes
|
* using the provided credentials. The first authentication failure takes
|
||||||
@@ -310,6 +322,20 @@ public class AuthenticationService {
|
|||||||
try {
|
try {
|
||||||
userContext = authProvider.getUserContext(authenticatedUser);
|
userContext = authProvider.getUserContext(authenticatedUser);
|
||||||
}
|
}
|
||||||
|
catch (GuacamoleInsufficientCredentialsException e) {
|
||||||
|
// Store state and expiration
|
||||||
|
String state = e.getState();
|
||||||
|
long expiration = e.getExpires();
|
||||||
|
String queryIdentifier = e.getQueryIdentifier();
|
||||||
|
String providerIdentifier = e.getProviderIdentifier();
|
||||||
|
|
||||||
|
resumableStateMap.put(state, new ResumableAuthenticationState(providerIdentifier,
|
||||||
|
queryIdentifier, expiration, credentials));
|
||||||
|
|
||||||
|
throw new GuacamoleAuthenticationProcessException("User "
|
||||||
|
+ "authentication aborted during initial "
|
||||||
|
+ "UserContext creation.", authProvider, e);
|
||||||
|
}
|
||||||
catch (GuacamoleException | RuntimeException | Error e) {
|
catch (GuacamoleException | RuntimeException | Error e) {
|
||||||
throw new GuacamoleAuthenticationProcessException("User "
|
throw new GuacamoleAuthenticationProcessException("User "
|
||||||
+ "authentication aborted during initial "
|
+ "authentication aborted during initial "
|
||||||
@@ -329,6 +355,82 @@ public class AuthenticationService {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Resumes authentication using given credentials if a matching resumable
|
||||||
|
* state is found.
|
||||||
|
*
|
||||||
|
* @param credentials
|
||||||
|
* The initial credentials containing the request object.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* Resumed credentials if a valid resumable state is found; otherwise,
|
||||||
|
* returns null.
|
||||||
|
*/
|
||||||
|
private Credentials resumeAuthentication(Credentials credentials) {
|
||||||
|
|
||||||
|
Credentials resumedCredentials = null;
|
||||||
|
|
||||||
|
// Retrieve signed State from the request
|
||||||
|
HttpServletRequest request = credentials.getRequest();
|
||||||
|
|
||||||
|
// Retrieve the provider id from the query parameters
|
||||||
|
String resumableProviderId = request.getParameter(Credentials.RESUME_QUERY);
|
||||||
|
// Check if a provider id is set
|
||||||
|
if (resumableProviderId == null || resumableProviderId.isEmpty()) {
|
||||||
|
// Return if a provider id is not set
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use an iterator to safely remove entries while iterating
|
||||||
|
Iterator<Map.Entry<String, ResumableAuthenticationState>> iterator = resumableStateMap.entrySet().iterator();
|
||||||
|
while (iterator.hasNext()) {
|
||||||
|
Map.Entry<String, ResumableAuthenticationState> entry = iterator.next();
|
||||||
|
ResumableAuthenticationState resumableState = entry.getValue();
|
||||||
|
|
||||||
|
// Check if the provider ID from the request matches the one in the map entry
|
||||||
|
boolean providerMatches = resumableProviderId.equals(resumableState.getProviderIdentifier());
|
||||||
|
if (!providerMatches) {
|
||||||
|
// If the provider doesn't match, skip to the next entry
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Use the query identifier from the entry to retrieve the corresponding state parameter
|
||||||
|
String stateQueryParameter = resumableState.getQueryIdentifier();
|
||||||
|
String stateFromParameter = request.getParameter(stateQueryParameter);
|
||||||
|
|
||||||
|
// Check if a state parameter is set
|
||||||
|
if (stateFromParameter == null || stateFromParameter.isEmpty()) {
|
||||||
|
// Remove and continue if`state is not provided or is empty
|
||||||
|
iterator.remove();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If the key in the entry (state) matches the state parameter provided in the request
|
||||||
|
if (entry.getKey().equals(stateFromParameter)) {
|
||||||
|
|
||||||
|
// Remove the current entry from the map
|
||||||
|
iterator.remove();
|
||||||
|
|
||||||
|
// Check if the resumableState has expired
|
||||||
|
if (!resumableState.isExpired()) {
|
||||||
|
|
||||||
|
// Set the actualCredentials to the credentials from the matched entry
|
||||||
|
resumedCredentials = resumableState.getCredentials();
|
||||||
|
|
||||||
|
if (resumedCredentials != null) {
|
||||||
|
resumedCredentials.setRequest(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// Exit the loop since we've found the matching state and it's unique
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return resumedCredentials;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Authenticates a user using the given credentials and optional
|
* Authenticates a user using the given credentials and optional
|
||||||
* authentication token, returning the authentication token associated with
|
* authentication token, returning the authentication token associated with
|
||||||
@@ -367,11 +469,16 @@ public class AuthenticationService {
|
|||||||
AuthenticatedUser authenticatedUser;
|
AuthenticatedUser authenticatedUser;
|
||||||
String authToken;
|
String authToken;
|
||||||
|
|
||||||
|
// Retrieve credentials if resuming authentication
|
||||||
|
Credentials actualCredentials = resumeAuthentication(credentials);
|
||||||
|
if (actualCredentials == null)
|
||||||
|
actualCredentials = credentials;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|
||||||
// Get up-to-date AuthenticatedUser and associated UserContexts
|
// Get up-to-date AuthenticatedUser and associated UserContexts
|
||||||
authenticatedUser = getAuthenticatedUser(existingSession, credentials);
|
authenticatedUser = getAuthenticatedUser(existingSession, actualCredentials);
|
||||||
List<DecoratedUserContext> userContexts = getUserContexts(existingSession, authenticatedUser, credentials);
|
List<DecoratedUserContext> userContexts = getUserContexts(existingSession, authenticatedUser, actualCredentials);
|
||||||
|
|
||||||
// Update existing session, if it exists
|
// Update existing session, if it exists
|
||||||
if (existingSession != null) {
|
if (existingSession != null) {
|
||||||
@@ -401,7 +508,7 @@ public class AuthenticationService {
|
|||||||
// Log and rethrow any authentication errors
|
// Log and rethrow any authentication errors
|
||||||
catch (GuacamoleAuthenticationProcessException e) {
|
catch (GuacamoleAuthenticationProcessException e) {
|
||||||
|
|
||||||
listenerService.handleEvent(new AuthenticationFailureEvent(credentials,
|
listenerService.handleEvent(new AuthenticationFailureEvent(actualCredentials,
|
||||||
e.getAuthenticationProvider(), e.getCause()));
|
e.getAuthenticationProvider(), e.getCause()));
|
||||||
|
|
||||||
// Rethrow exception
|
// Rethrow exception
|
||||||
|
@@ -0,0 +1,128 @@
|
|||||||
|
/*
|
||||||
|
* 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.rest.auth;
|
||||||
|
|
||||||
|
import org.apache.guacamole.net.auth.Credentials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Encapsulates the state information required for resuming an authentication
|
||||||
|
* process. This includes an expiration timestamp to determine state validity
|
||||||
|
* and the original credentials submitted by the user.
|
||||||
|
*/
|
||||||
|
public class ResumableAuthenticationState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The timestamp at which this state should no longer be considered valid,
|
||||||
|
* measured in milliseconds since the Unix epoch.
|
||||||
|
*/
|
||||||
|
private long expirationTimestamp;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The original user credentials that were submitted at the start of the
|
||||||
|
* authentication process.
|
||||||
|
*/
|
||||||
|
private Credentials credentials;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique string identifying the authentication provider related to the state.
|
||||||
|
* This field allows the client to know which provider's authentication process
|
||||||
|
* should be resumed using this state.
|
||||||
|
*/
|
||||||
|
private String providerIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A unique string that can be used to identify a specific query within the
|
||||||
|
* authentication process for the identified provider. This identifier can
|
||||||
|
* help the resumption of an authentication process.
|
||||||
|
*/
|
||||||
|
private String queryIdentifier;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a new ResumableAuthenticationState object with the specified
|
||||||
|
* expiration timestamp and user credentials.
|
||||||
|
*
|
||||||
|
* @param providerIdentifier
|
||||||
|
* The identifier of the authentication provider to which this resumable state pertains.
|
||||||
|
*
|
||||||
|
* @param queryIdenifier
|
||||||
|
* The identifier of the specific query within the provider's
|
||||||
|
* authentication process that this state corresponds to.
|
||||||
|
*
|
||||||
|
* @param expirationTimestamp
|
||||||
|
* The timestamp in milliseconds since the Unix epoch when this state
|
||||||
|
* expires and can no longer be used to resume authentication.
|
||||||
|
*
|
||||||
|
* @param credentials
|
||||||
|
* The Credentials object initially submitted by the user and associated
|
||||||
|
* with this resumable state.
|
||||||
|
*/
|
||||||
|
public ResumableAuthenticationState(String providerIdentifier, String queryIdentifier,
|
||||||
|
long expirationTimestamp, Credentials credentials) {
|
||||||
|
this.expirationTimestamp = expirationTimestamp;
|
||||||
|
this.credentials = credentials;
|
||||||
|
this.providerIdentifier = providerIdentifier;
|
||||||
|
this.queryIdentifier = queryIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks if this resumable state has expired based on the stored expiration
|
||||||
|
* timestamp and the current system time.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* True if the current system time is after the expiration timestamp,
|
||||||
|
* indicating that the state is expired; false otherwise.
|
||||||
|
*/
|
||||||
|
public boolean isExpired() {
|
||||||
|
return System.currentTimeMillis() >= expirationTimestamp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the original credentials associated with this resumable state.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The Credentials object containing user details that were submitted
|
||||||
|
* when the state was created.
|
||||||
|
*/
|
||||||
|
public Credentials getCredentials() {
|
||||||
|
return this.credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the identifier of the authentication provider associated with this state.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The identifier of the authentication provider, providing context for this state
|
||||||
|
* within the overall authentication sequence.
|
||||||
|
*/
|
||||||
|
public String getProviderIdentifier() {
|
||||||
|
return this.providerIdentifier;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the identifier for a specific query in the authentication
|
||||||
|
* process that is associated with this state.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* The query identifier used for retrieving a value representing the state within
|
||||||
|
* the provider's authentication process that should be resumed.
|
||||||
|
*/
|
||||||
|
public String getQueryIdentifier() {
|
||||||
|
return this.queryIdentifier;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user