From 2f1bd7caa3479190df7eca5ee7991c490914911b Mon Sep 17 00:00:00 2001 From: Sebastian Becker Date: Thu, 10 Oct 2024 16:56:04 +0200 Subject: [PATCH] !feat: add authentication support (#42) --------- Signed-off-by: Jared Weinfurtner Signed-off-by: Sebastian Becker --- .gitignore | 2 + .pre-commit-config.yaml | 4 +- .../LICENSE.txt | 202 +++++++++++++++ .../com.nimbusds_content-type/COPYRIGHT.txt | 14 ++ .../com.nimbusds_content-type/LICENSE.txt | 202 +++++++++++++++ .../com.nimbusds_lang-tag/COPYRIGHT.txt | 14 ++ .../com.nimbusds_lang-tag/LICENSE.txt | 202 +++++++++++++++ .../COPYRIGHT.txt | 14 ++ .../com.nimbusds_nimbus-jose-jwt/LICENSE.txt | 202 +++++++++++++++ .../COPYRIGHT.txt | 14 ++ .../com.nimbusds_oauth2-oidc-sdk/LICENSE.txt | 202 +++++++++++++++ .../net.minidev_accessors-smart/LICENSE | 202 +++++++++++++++ .../net.minidev_json-smart/LICENSE | 202 +++++++++++++++ 3RD-PARTY-LICENSES/org.ow2.asm_asm/LICENSE | 27 ++ 3RD-PARTY-LICENSES/sbom.xml | 214 ++++++++++------ pom.xml | 46 ++-- .../AmphoraClientCliCommandRunner.java | 13 +- .../command/CastorClientCliCommandRunner.java | 15 +- .../EphemeralClientCliCommandRunner.java | 12 +- .../cli/configuration/VcpConfiguration.java | 167 +++++++----- .../carbynestack/cli/login/LoginCommand.java | 167 +++++++----- ...2AuthenticationCodeCallbackHttpServer.java | 104 +++++--- .../io/carbynestack/cli/login/VcpToken.java | 29 ++- .../carbynestack/cli/login/VcpTokenStore.java | 143 ++++++----- .../carbynestack/cli/util/KeyStoreUtil.java | 51 ---- .../io/carbynestack/cli/util/OAuthUtil.java | 60 +++++ .../ConfigurationMessageBundle.properties | 14 +- .../cli/TemporaryConfiguration.java | 10 +- .../cli/configuration/ConfigurationUtil.java | 14 +- .../configuration/VcpConfigurationTest.java | 12 +- .../cli/login/LoginCommandTest.java | 238 +++++++++--------- ...henticationCodeCallbackHttpServerTest.java | 50 ++-- .../cli/login/VcpTokenStoreTest.java | 62 ++--- .../carbynestack/cli/util/OAuthUtilTest.java | 114 +++++++++ .../io/carbynestack/cli/util/TokenUtils.java | 37 ++- src/test/resources/id_token.json | 8 + 36 files changed, 2478 insertions(+), 605 deletions(-) create mode 100644 3RD-PARTY-LICENSES/com.github.stephenc.jcip_jcip-annotations/LICENSE.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_content-type/COPYRIGHT.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_content-type/LICENSE.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_lang-tag/COPYRIGHT.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_lang-tag/LICENSE.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/COPYRIGHT.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/LICENSE.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/COPYRIGHT.txt create mode 100644 3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/LICENSE.txt create mode 100644 3RD-PARTY-LICENSES/net.minidev_accessors-smart/LICENSE create mode 100644 3RD-PARTY-LICENSES/net.minidev_json-smart/LICENSE create mode 100644 3RD-PARTY-LICENSES/org.ow2.asm_asm/LICENSE delete mode 100644 src/main/java/io/carbynestack/cli/util/KeyStoreUtil.java create mode 100644 src/main/java/io/carbynestack/cli/util/OAuthUtil.java create mode 100644 src/test/java/io/carbynestack/cli/util/OAuthUtilTest.java create mode 100644 src/test/resources/id_token.json diff --git a/.gitignore b/.gitignore index ea93602..531fd3a 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ target/ *.iml .sdkmanrc + +.http diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6d429a3..a547692 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -34,9 +34,9 @@ repos: - "80" additional_dependencies: - mdformat-gfm - exclude: ^3RD-PARTY-LICENSES$ + exclude: ^CHANGELOG.md$|^3RD-PARTY-LICENSES$ - repo: https://github.com/igorshubovych/markdownlint-cli rev: v0.33.0 hooks: - id: markdownlint - exclude: ^README.md$|.*/3RD-PARTY-LICENSES/.* + exclude: ^README.md$|^CHANGELOG.md$|.*/3RD-PARTY-LICENSES/.* diff --git a/3RD-PARTY-LICENSES/com.github.stephenc.jcip_jcip-annotations/LICENSE.txt b/3RD-PARTY-LICENSES/com.github.stephenc.jcip_jcip-annotations/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.github.stephenc.jcip_jcip-annotations/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_content-type/COPYRIGHT.txt b/3RD-PARTY-LICENSES/com.nimbusds_content-type/COPYRIGHT.txt new file mode 100644 index 0000000..e0f0264 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_content-type/COPYRIGHT.txt @@ -0,0 +1,14 @@ +Nimbus Content Type + +Copyright 2020, Connect2id Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_content-type/LICENSE.txt b/3RD-PARTY-LICENSES/com.nimbusds_content-type/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_content-type/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_lang-tag/COPYRIGHT.txt b/3RD-PARTY-LICENSES/com.nimbusds_lang-tag/COPYRIGHT.txt new file mode 100644 index 0000000..e0e1c59 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_lang-tag/COPYRIGHT.txt @@ -0,0 +1,14 @@ +Nimbus Language Tags + +Copyright 2012-2022, Connect2id Ltd. + +Licensed under the Apache License, Version 2.0 (the "License"); you may not use +this file except in compliance with the License. You may obtain a copy of the +License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software distributed +under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR +CONDITIONS OF ANY KIND, either express or implied. See the License for the +specific language governing permissions and limitations under the License. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_lang-tag/LICENSE.txt b/3RD-PARTY-LICENSES/com.nimbusds_lang-tag/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_lang-tag/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/COPYRIGHT.txt b/3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/COPYRIGHT.txt new file mode 100644 index 0000000..ec6d868 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/COPYRIGHT.txt @@ -0,0 +1,14 @@ +Nimbus JOSE + JWT + +Copyright 2012 - 2024, Connect2id Ltd. + +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. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/LICENSE.txt b/3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_nimbus-jose-jwt/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/COPYRIGHT.txt b/3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/COPYRIGHT.txt new file mode 100644 index 0000000..6831cef --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/COPYRIGHT.txt @@ -0,0 +1,14 @@ +Nimbus OAuth 2.0 SDK with OpenID Connect extensions + +Copyright 2012-2024, Connect2id Ltd and contributors. + +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. diff --git a/3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/LICENSE.txt b/3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/LICENSE.txt new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/3RD-PARTY-LICENSES/com.nimbusds_oauth2-oidc-sdk/LICENSE.txt @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/3RD-PARTY-LICENSES/net.minidev_accessors-smart/LICENSE b/3RD-PARTY-LICENSES/net.minidev_accessors-smart/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/3RD-PARTY-LICENSES/net.minidev_accessors-smart/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/3RD-PARTY-LICENSES/net.minidev_json-smart/LICENSE b/3RD-PARTY-LICENSES/net.minidev_json-smart/LICENSE new file mode 100644 index 0000000..8f71f43 --- /dev/null +++ b/3RD-PARTY-LICENSES/net.minidev_json-smart/LICENSE @@ -0,0 +1,202 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/3RD-PARTY-LICENSES/org.ow2.asm_asm/LICENSE b/3RD-PARTY-LICENSES/org.ow2.asm_asm/LICENSE new file mode 100644 index 0000000..c71bb7b --- /dev/null +++ b/3RD-PARTY-LICENSES/org.ow2.asm_asm/LICENSE @@ -0,0 +1,27 @@ +ASM: a very small and fast Java bytecode manipulation framework +Copyright (c) 2000-2011 INRIA, France Telecom +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. Neither the name of the copyright holders nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +THE POSSIBILITY OF SUCH DAMAGE. diff --git a/3RD-PARTY-LICENSES/sbom.xml b/3RD-PARTY-LICENSES/sbom.xml index ea39202..51c7263 100644 --- a/3RD-PARTY-LICENSES/sbom.xml +++ b/3RD-PARTY-LICENSES/sbom.xml @@ -4,7 +4,7 @@ amphora-common io.carbynestack amphora-common - 0.1.1 + 0.2.0 Apache-2.0 @@ -16,7 +16,7 @@ amphora-java-client io.carbynestack amphora-java-client - 0.1.1 + 0.2.0 Apache-2.0 @@ -141,11 +141,63 @@ + + Apache Log4j API + org.apache.logging.log4j + log4j-api + 2.20.0 + https://logging.apache.org/log4j/2.x/log4j-api/ + + + Apache License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + Apache Log4j Core + org.apache.logging.log4j + log4j-core + 2.24.1 + https://logging.apache.org/log4j/2.x/log4j/log4j-core/ + + + Apache-2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt + + + + + asm + org.ow2.asm + asm + 7.0 + http://asm.ow2.org/ + + + BSD + http://asm.ow2.org/license.html + + + + + ASM based accessors helper used by json-smart + net.minidev + accessors-smart + 2.5.1 + https://urielch.github.io/ + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + Carbyne Stack Ephemeral Java Client io.carbynestack ephemeral-java-client - 0.1-SNAPSHOT-2804677120-20-efc7f8d + 0.2.0 Apache-2.0 @@ -157,7 +209,7 @@ Carbyne Stack Java HTTP Client io.carbynestack java-http-client - 0.1-SNAPSHOT-4075044562-9-8ffab9c + 0.2.0 Apache-2.0 @@ -169,7 +221,7 @@ Carbyne Stack MP-SPDZ Integration Utilities io.carbynestack mp-spdz-integration - 0.2-SNAPSHOT-3541842672-11-c754bbb + 0.2.2 Apache-2.0 @@ -181,7 +233,7 @@ castor-common io.carbynestack castor-common - 0.1-SNAPSHOT-4191841095-22-1721229 + 0.2.0 Apache-2.0 @@ -193,7 +245,7 @@ castor-java-client io.carbynestack castor-java-client - 0.1-SNAPSHOT-4191841095-22-1721229 + 0.2.0 Apache-2.0 @@ -205,7 +257,7 @@ castor-upload-java-client io.carbynestack castor-upload-java-client - 0.1-SNAPSHOT-4191841095-22-1721229 + 0.2.0 Apache-2.0 @@ -369,6 +421,19 @@ + + JCIP Annotations under Apache License + com.github.stephenc.jcip + jcip-annotations + 1.0-1 + http://stephenc.github.com/jcip-annotations + + + Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + jcommander com.beust @@ -382,6 +447,19 @@ + + JSON Small and Fast Parser + net.minidev + json-smart + 2.5.1 + https://urielch.github.io/ + + + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + JUL to SLF4J bridge org.slf4j @@ -396,67 +474,80 @@ - Project Lombok - org.projectlombok - lombok - 1.18.24 - https://projectlombok.org + Nimbus Content Type + com.nimbusds + content-type + 2.3 + https://bitbucket.org/connect2id/nimbus-content-type - The MIT License - https://projectlombok.org/LICENSE + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt - reload4j - ch.qos.reload4j - reload4j - 1.2.24 - https://reload4j.qos.ch + Nimbus JOSE+JWT + com.nimbusds + nimbus-jose-jwt + 9.39.1 + https://bitbucket.org/connect2id/nimbus-jose-jwt The Apache Software License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt + https://www.apache.org/licenses/LICENSE-2.0.txt - ScribeJava APIs - com.github.scribejava - scribejava-apis - 8.3.1 - https://github.com/scribejava/scribejava/scribejava-apis + Nimbus LangTag + com.nimbusds + lang-tag + 1.7 + https://bitbucket.org/connect2id/nimbus-language-tags - MIT - https://github.com/scribejava/scribejava/blob/master/LICENSE.txt + The Apache Software License, Version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.txt - ScribeJava Core - com.github.scribejava - scribejava-core - 8.3.1 - https://github.com/scribejava/scribejava/scribejava-core + OAuth 2.0 SDK with OpenID Connect extensions + com.nimbusds + oauth2-oidc-sdk + 11.12 + https://bitbucket.org/connect2id/oauth-2.0-sdk-with-openid-connect-extensions - MIT - https://github.com/scribejava/scribejava/blob/master/LICENSE.txt + Apache License, version 2.0 + https://www.apache.org/licenses/LICENSE-2.0.html - ScribeJava Java 8+ compatibility stuff - com.github.scribejava - scribejava-java8 - 8.3.1 - https://github.com/scribejava/scribejava/scribejava-java8 + Project Lombok + org.projectlombok + lombok + 1.18.24 + https://projectlombok.org + + + The MIT License + https://projectlombok.org/LICENSE + + + + + reload4j + ch.qos.reload4j + reload4j + 1.2.24 + https://reload4j.qos.ch - MIT - https://github.com/scribejava/scribejava/blob/master/LICENSE.txt + The Apache Software License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt @@ -616,45 +707,6 @@ - - spring-security-core - org.springframework.security - spring-security-core - 5.5.8 - https://spring.io/projects/spring-security - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - - - - - spring-security-crypto - org.springframework.security - spring-security-crypto - 5.5.8 - https://spring.io/projects/spring-security - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - - - - - spring-security-web - org.springframework.security - spring-security-web - 5.5.8 - https://spring.io/projects/spring-security - - - Apache License, Version 2.0 - https://www.apache.org/licenses/LICENSE-2.0 - - - tomcat-annotations-api org.apache.tomcat diff --git a/pom.xml b/pom.xml index bbc6c09..68ce2a7 100644 --- a/pom.xml +++ b/pom.xml @@ -1,11 +1,11 @@ - + 4.0.0 cli io.carbynestack @@ -58,11 +58,12 @@ 2.0.0 - 0.1.1 - 0.1-SNAPSHOT-4191841095-22-1721229 - 0.1-SNAPSHOT-4191841095-22-1721229 - 0.1-SNAPSHOT-4191841095-22-1721229 - 0.1-SNAPSHOT-2804677120-20-efc7f8d + 0.2.0 + 0.2.0 + 0.2.0 + 0.2.0 + 0.2.0 + 0.2.0 2.11.0 @@ -75,9 +76,8 @@ 3.11.2 2.0.9 1.2.24 - 8.3.1 2.0.6 - 2.16.0 + 2.24.1 1.19.0 2.2.8.Final 0.10.4 @@ -85,6 +85,11 @@ + + io.carbynestack + java-http-client + ${cs-java-client.version} + io.carbynestack amphora-java-client @@ -132,16 +137,16 @@ jackson-core ${jackson.version} - - com.github.scribejava - scribejava-apis - ${scribejava.version} - io.undertow undertow-core ${undertow.version} + + com.nimbusds + oauth2-oidc-sdk + 11.12 + io.vavr vavr @@ -152,6 +157,12 @@ commons-text ${apache.commons.text.version} + + org.apache.logging.log4j + log4j-core + ${log4j.version} + + org.projectlombok lombok @@ -211,6 +222,13 @@ ${mockito.version} test + + org.mockito + mockito-inline + ${mockito.version} + test + + org.powermock powermock-api-mockito2 diff --git a/src/main/java/io/carbynestack/cli/client/amphora/command/AmphoraClientCliCommandRunner.java b/src/main/java/io/carbynestack/cli/client/amphora/command/AmphoraClientCliCommandRunner.java index 801d338..3482811 100644 --- a/src/main/java/io/carbynestack/cli/client/amphora/command/AmphoraClientCliCommandRunner.java +++ b/src/main/java/io/carbynestack/cli/client/amphora/command/AmphoraClientCliCommandRunner.java @@ -1,12 +1,12 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 */ package io.carbynestack.cli.client.amphora.command; -import static io.carbynestack.cli.client.amphora.AmphoraClientCli.*; +import static io.carbynestack.cli.client.amphora.AmphoraClientCli.AMPHORA_MESSAGE_BUNDLE; import com.google.common.collect.Maps; import io.carbynestack.amphora.client.AmphoraClient; @@ -23,7 +23,6 @@ import io.carbynestack.cli.login.CsCliLoginException; import io.carbynestack.cli.login.VcpToken; import io.carbynestack.cli.login.VcpTokenStore; -import io.carbynestack.cli.util.KeyStoreUtil; import io.vavr.control.Option; import io.vavr.control.Try; import java.util.Arrays; @@ -61,13 +60,15 @@ public AmphoraClientCliCommandRunner(T config) map -> (BearerTokenProvider) amphoraServiceUri -> - map.get(amphoraServiceUri).getAccessToken()) + map.get(amphoraServiceUri).getIdToken()) .map(amphoraClientBuilder::bearerTokenProvider); } - KeyStoreUtil.tempKeyStoreForPems(configuration.getTrustedCertificates()) - .peek(amphoraClientBuilder::addTrustedCertificate); if (configuration.isNoSslValidation()) { amphoraClientBuilder.withoutSslCertificateValidation(); + } else { + configuration + .getTrustedCertificates() + .forEach(p -> amphoraClientBuilder.addTrustedCertificate(p.toFile())); } return amphoraClientBuilder.build(); })) diff --git a/src/main/java/io/carbynestack/cli/client/castor/command/CastorClientCliCommandRunner.java b/src/main/java/io/carbynestack/cli/client/castor/command/CastorClientCliCommandRunner.java index b03ada0..386ea0f 100644 --- a/src/main/java/io/carbynestack/cli/client/castor/command/CastorClientCliCommandRunner.java +++ b/src/main/java/io/carbynestack/cli/client/castor/command/CastorClientCliCommandRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -21,7 +21,6 @@ import io.carbynestack.cli.login.CsCliLoginException; import io.carbynestack.cli.login.VcpToken; import io.carbynestack.cli.login.VcpTokenStore; -import io.carbynestack.cli.util.KeyStoreUtil; import io.vavr.control.Option; import io.vavr.control.Try; import java.io.File; @@ -71,8 +70,7 @@ abstract class CastorClientCliCommandRunner BearerTokenProvider.builder() .bearerToken( - vcpConfiguration.getCastorServiceUri(), - t.getAccessToken()) + vcpConfiguration.getCastorServiceUri(), t.getIdToken()) .build()) .peek(builder::withBearerTokenProvider); return builder.build(); @@ -94,18 +92,19 @@ abstract class CastorClientCliCommandRunner intraVcpClientBuilder.withTrustedCertificate(p.toFile())); } token .map( t -> BearerTokenProvider.builder() .bearerToken( - vcpConfiguration.getCastorServiceUri(), - t.getAccessToken()) + vcpConfiguration.getCastorServiceUri(), t.getIdToken()) .build()) .peek(intraVcpClientBuilder::withBearerTokenProvider); return intraVcpClientBuilder.build(); diff --git a/src/main/java/io/carbynestack/cli/client/ephemeral/command/EphemeralClientCliCommandRunner.java b/src/main/java/io/carbynestack/cli/client/ephemeral/command/EphemeralClientCliCommandRunner.java index 204983f..50a8c4f 100644 --- a/src/main/java/io/carbynestack/cli/client/ephemeral/command/EphemeralClientCliCommandRunner.java +++ b/src/main/java/io/carbynestack/cli/client/ephemeral/command/EphemeralClientCliCommandRunner.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -18,7 +18,6 @@ import io.carbynestack.cli.login.CsCliLoginException; import io.carbynestack.cli.login.VcpToken; import io.carbynestack.cli.login.VcpTokenStore; -import io.carbynestack.cli.util.KeyStoreUtil; import io.carbynestack.ephemeral.client.EphemeralEndpoint; import io.carbynestack.ephemeral.client.EphemeralMultiClient; import io.vavr.control.Option; @@ -54,9 +53,12 @@ private EphemeralMultiClient createEphemeralClient(T config) .withEndpoints(endpoints) .withSslCertificateValidation(!configuration.isNoSslValidation()); tokens.forEach( - t -> builder.withBearerTokenProvider(uri -> t.get(uri).getAccessToken())); - KeyStoreUtil.tempKeyStoreForPems(configuration.getTrustedCertificates()) - .peek(builder::withTrustedCertificate); + t -> builder.withBearerTokenProvider(uri -> t.get(uri).getIdToken())); + if (!configuration.isNoSslValidation()) { + configuration + .getTrustedCertificates() + .forEach(p -> builder.withTrustedCertificate(p.toFile())); + } return builder.build(); })) .getOrElseThrow( diff --git a/src/main/java/io/carbynestack/cli/configuration/VcpConfiguration.java b/src/main/java/io/carbynestack/cli/configuration/VcpConfiguration.java index a816643..d254fc9 100644 --- a/src/main/java/io/carbynestack/cli/configuration/VcpConfiguration.java +++ b/src/main/java/io/carbynestack/cli/configuration/VcpConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -28,6 +28,8 @@ public class VcpConfiguration { static final String AMPHORA_URL_ENV_KEY_FORMAT = "CS_VCP_{0}_AMPHORA_URL"; static final String CASTOR_URL_ENV_KEY_FORMAT = "CS_VCP_{0}_CASTOR_URL"; static final String EPHEMERAL_URL_ENV_KEY_FORMAT = "CS_VCP_{0}_EPHEMERAL_URL"; + static final String OAUTH2_AUTH_ENDPOINT_URI = "CS_VCP_{0}_OAUTH2_AUTH_ENDPOINT_URI"; + static final String OAUTH2_TOKEN_ENDPOINT_URI = "CS_VCP_{0}_OAUTH2_TOKEN_ENDPOINT_URI"; static final String OAUTH2_CLIENT_ID_ENV_KEY_FORMAT = "CS_VCP_{0}_OAUTH2_CLIENT_ID"; static final String OAUTH2_CALLBACK_URL_ENV_KEY_FORMAT = "CS_VCP_{0}_OAUTH2_CALLBACK_URL"; static final String AMPHORA_URL_FORMAT = "{0}amphora"; @@ -36,64 +38,71 @@ public class VcpConfiguration { private static final ResourceBundle MESSAGES = ResourceBundle.getBundle(CONFIGURATION_MESSAGE_BUNDLE); - - @JsonProperty(value = "id", required = true, index = 10) - private int providerNumber; - URI baseUrl; AmphoraServiceUri amphoraServiceUri; CastorServiceUri castorServiceUri; URI ephemeralServiceUrl; String oAuth2clientId; + URI oAuth2AuthEndpointUri; + URI oAuth2TokenEndpointUri; URI oAuth2CallbackUrl; + @JsonProperty(value = "id", required = true, index = 10) + private int providerNumber; + VcpConfiguration(int providerNumber) { this.providerNumber = providerNumber; } void configure() throws CsCliConfigurationException { try { - System.out.println(String.format("Configuring Provider #%d", providerNumber)); - System.out.print( - String.format( - "\t%s", - MessageFormat.format( - MESSAGES.getString("configuration.request.vcp.base-url"), getActualBaseUrl()))); + System.out.printf("Configuring Provider #%d%n", providerNumber); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.base-url"), getActualBaseUrl())); updateBaseUrlIfChanged(getActualBaseUrl(), readOrDefault(getActualBaseUrl())); - System.out.print( - String.format( - "\t%s", - MessageFormat.format( - MESSAGES.getString("configuration.request.vcp.amphora-service-url"), - getActualAmphoraServiceUri()))); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.amphora-service-url"), + getActualAmphoraServiceUri())); amphoraServiceUri = new AmphoraServiceUri(readOrDefault(getActualAmphoraServiceUri())); - System.out.print( - String.format( - "\t%s", - MessageFormat.format( - MESSAGES.getString("configuration.request.vcp.castor-service-url"), - getActualCastorServiceUri()))); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.castor-service-url"), + getActualCastorServiceUri())); castorServiceUri = new CastorServiceUri(readOrDefault(getActualCastorServiceUri())); - System.out.print( - String.format( - "\t%s", - MessageFormat.format( - MESSAGES.getString("configuration.request.vcp.ephemeral-service-url"), - getActualEphemeralServiceUrl()))); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.ephemeral-service-url"), + getActualEphemeralServiceUrl())); ephemeralServiceUrl = URI.create(readOrDefault(getActualEphemeralServiceUrl())); - System.out.print( - String.format( - "\t%s", - MessageFormat.format( - MESSAGES.getString("configuration.request.vcp.oauth2-client-id"), - getActualOAuth2ClientId()))); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.oauth2-client-id"), + getActualOAuth2ClientId())); oAuth2clientId = readOrDefault(getActualOAuth2ClientId()); - System.out.print( - String.format( - "\t%s", - MessageFormat.format( - MESSAGES.getString("configuration.request.vcp.oauth2-callback-url"), - getActualOAuth2CallbackUrl()))); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.oauth2-auth-endpoint-uri"), + getOauth2AuthEndpointUri())); + oAuth2AuthEndpointUri = URI.create(readOrDefault(getActualOauth2AuthEndpointUri())); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.oauth2-token-endpoint-uri"), + getOauth2AuthEndpointUri())); + oAuth2TokenEndpointUri = URI.create(readOrDefault(getActualOauth2TokenEndpointUri())); + System.out.printf( + "\t%s", + MessageFormat.format( + MESSAGES.getString("configuration.request.vcp.oauth2-callback-url"), + getActualOAuth2CallbackUrl())); oAuth2CallbackUrl = URI.create(readOrDefault(getActualOAuth2CallbackUrl())); } catch (NoSuchElementException | IllegalStateException | IllegalArgumentException e) { throw new CsCliConfigurationException(MESSAGES.getString("configuration.failed"), e); @@ -105,11 +114,6 @@ private String getActualBaseUrl() { return baseUrl != null ? baseUrl.toString() : ""; } - @JsonProperty(value = "baseUrl", required = true, index = 11) - private void setBaseUrl(String baseUrl) { - this.baseUrl = URI.create(baseUrl); - } - private void updateBaseUrlIfChanged(String oldValue, String newValue) { if (!newValue.equals(oldValue)) { baseUrl = URI.create(newValue); @@ -126,6 +130,11 @@ public URI getBaseUrl() { return baseUrl; } + @JsonProperty(value = "baseUrl", required = true, index = 11) + private void setBaseUrl(String baseUrl) { + this.baseUrl = URI.create(baseUrl); + } + public AmphoraServiceUri getAmphoraServiceUri() { return System.getenv(MessageFormat.format(AMPHORA_URL_ENV_KEY_FORMAT, providerNumber)) != null ? new AmphoraServiceUri( @@ -134,13 +143,13 @@ public AmphoraServiceUri getAmphoraServiceUri() { } @JsonProperty(value = "amphoraServiceUrl", required = true, index = 12) - private String getActualAmphoraServiceUri() { - return amphoraServiceUri != null ? amphoraServiceUri.getServiceUri().toString() : ""; + private void setAmphoraServiceUri(String amphoraServiceAddress) { + this.amphoraServiceUri = new AmphoraServiceUri(amphoraServiceAddress); } @JsonProperty(value = "amphoraServiceUrl", required = true, index = 12) - private void setAmphoraServiceUri(String amphoraServiceAddress) { - this.amphoraServiceUri = new AmphoraServiceUri(amphoraServiceAddress); + private String getActualAmphoraServiceUri() { + return amphoraServiceUri != null ? amphoraServiceUri.getServiceUri().toString() : ""; } public CastorServiceUri getCastorServiceUri() { @@ -151,13 +160,13 @@ public CastorServiceUri getCastorServiceUri() { } @JsonProperty(value = "castorServiceUrl", required = true, index = 13) - private String getActualCastorServiceUri() { - return castorServiceUri != null ? castorServiceUri.getRestServiceUri().toString() : ""; + private void setCastorServiceUri(String castorServiceAddress) { + this.castorServiceUri = new CastorServiceUri(castorServiceAddress); } @JsonProperty(value = "castorServiceUrl", required = true, index = 13) - private void setCastorServiceUri(String castorServiceAddress) { - this.castorServiceUri = new CastorServiceUri(castorServiceAddress); + private String getActualCastorServiceUri() { + return castorServiceUri != null ? castorServiceUri.getRestServiceUri().toString() : ""; } public URI getEphemeralServiceUrl() { @@ -185,13 +194,13 @@ public String getOAuth2ClientId() { } @JsonProperty(value = "oauth2ClientId", required = true, index = 15) - private String getActualOAuth2ClientId() { - return oAuth2clientId != null ? oAuth2clientId : ""; + public void setOAuth2ClientId(String oAuth2ClientId) { + this.oAuth2clientId = oAuth2ClientId; } @JsonProperty(value = "oauth2ClientId", required = true, index = 15) - private void setOAuth2ClientId(String oAuth2ClientId) { - this.oAuth2clientId = oAuth2ClientId; + public String getActualOAuth2ClientId() { + return oAuth2clientId != null ? oAuth2clientId : ""; } public URI getOAuth2CallbackUrl() { @@ -202,14 +211,46 @@ public URI getOAuth2CallbackUrl() { : oAuth2CallbackUrl; } + @JsonProperty(value = "oauth2CallbackUrl", required = true, index = 16) + private void setOAuth2CallbackUrl(String oAuth2CallbackUrl) { + this.oAuth2CallbackUrl = URI.create(oAuth2CallbackUrl); + } + @JsonProperty(value = "oauth2CallbackUrl", required = true, index = 16) private String getActualOAuth2CallbackUrl() { return oAuth2CallbackUrl != null ? oAuth2CallbackUrl.toString() : ""; } - @JsonProperty(value = "oauth2CallbackUrl", required = true, index = 16) - private void setOAuth2CallbackUrl(String oAuth2CallbackUrl) { - this.oAuth2CallbackUrl = URI.create(oAuth2CallbackUrl); + @JsonProperty(value = "oauth2AuthEndpointUri", required = true, index = 17) + private String getActualOauth2AuthEndpointUri() { + return oAuth2AuthEndpointUri != null ? oAuth2AuthEndpointUri.toString() : ""; + } + + public URI getOauth2AuthEndpointUri() { + return System.getenv(MessageFormat.format(OAUTH2_AUTH_ENDPOINT_URI, providerNumber)) != null + ? URI.create(System.getenv(MessageFormat.format(OAUTH2_AUTH_ENDPOINT_URI, providerNumber))) + : oAuth2AuthEndpointUri; + } + + @JsonProperty(value = "oauth2AuthEndpointUri", required = true, index = 17) + public void setOauth2AuthEndpointUri(String oAuth2AuthEndpointUri) { + this.oAuth2AuthEndpointUri = URI.create(oAuth2AuthEndpointUri); + } + + @JsonProperty(value = "oauth2TokenEndpointUri", required = true, index = 18) + private String getActualOauth2TokenEndpointUri() { + return oAuth2TokenEndpointUri != null ? oAuth2TokenEndpointUri.toString() : ""; + } + + public URI getOauth2TokenEndpointUri() { + return System.getenv(MessageFormat.format(OAUTH2_TOKEN_ENDPOINT_URI, providerNumber)) != null + ? URI.create(System.getenv(MessageFormat.format(OAUTH2_TOKEN_ENDPOINT_URI, providerNumber))) + : oAuth2TokenEndpointUri; + } + + @JsonProperty(value = "oauth2TokenEndpointUri", required = true, index = 18) + public void setOauth2TokenEndpointUri(String oAuth2TokenEndpointUri) { + this.oAuth2TokenEndpointUri = URI.create(oAuth2TokenEndpointUri); } @Override @@ -227,6 +268,10 @@ public String toString() { + ephemeralServiceUrl + ", oauth2ClientId=" + oAuth2clientId + + ", oauth2AuthEndpointUri=" + + oAuth2AuthEndpointUri + + ", oauth2TokenEndpointUri=" + + oAuth2TokenEndpointUri + ", oauth2CallbackUrl=" + oAuth2CallbackUrl + '}'; diff --git a/src/main/java/io/carbynestack/cli/login/LoginCommand.java b/src/main/java/io/carbynestack/cli/login/LoginCommand.java index da2c324..34bdc59 100644 --- a/src/main/java/io/carbynestack/cli/login/LoginCommand.java +++ b/src/main/java/io/carbynestack/cli/login/LoginCommand.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -8,23 +8,33 @@ import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; -import com.github.scribejava.apis.MicrosoftAzureActiveDirectory20Api; -import com.github.scribejava.core.builder.ServiceBuilder; -import com.github.scribejava.core.oauth.AccessTokenRequestParams; -import com.github.scribejava.core.oauth.OAuth20Service; import com.google.common.collect.Lists; +import com.nimbusds.oauth2.sdk.*; +import com.nimbusds.oauth2.sdk.http.HTTPRequest; +import com.nimbusds.oauth2.sdk.id.ClientID; +import com.nimbusds.oauth2.sdk.id.State; +import com.nimbusds.openid.connect.sdk.AuthenticationRequest; +import com.nimbusds.openid.connect.sdk.Nonce; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponseParser; import io.carbynestack.cli.configuration.Configuration; import io.carbynestack.cli.configuration.VcpConfiguration; import io.carbynestack.cli.exceptions.CsCliConfigurationException; +import io.carbynestack.cli.util.OAuthUtil; import io.vavr.control.Either; import io.vavr.control.Option; import io.vavr.control.Try; +import java.io.IOException; import java.net.BindException; import java.net.URI; +import java.nio.file.Path; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.util.List; import java.util.ResourceBundle; import java.util.function.BiFunction; -import java.util.function.Function; import lombok.Getter; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.Range; @@ -38,60 +48,47 @@ commandNames = {LoginCommand.COMMAND_NAME}) public class LoginCommand { - public enum LoginCommandError implements AuthenticationError { - - /** Something went wrong when retrieving the access token */ - FAILED_TO_GET_ACCESS_TOKEN, - - /** No free port is available for launching the webserver for the callback */ - PORT_RANGE_EXHAUSTION, - - /** An unexpected error condition occurred while performing the login */ - UNEXPECTED - } - public static final String LOGIN_MESSAGE_BUNDLE = "LoginMessageBundle"; public static final String COMMAND_NAME = "login"; - - private static final ResourceBundle MESSAGES = ResourceBundle.getBundle(LOGIN_MESSAGE_BUNDLE); - private static final String[] SCOPES = - new String[] {"openid", "email", "profile", "offline_access"}; - /* Ephemeral port range used by many Linux kernels. */ static final Range DEFAULT_CALLBACK_PORTS = Range.between(32768, 61000); - static final String TENANT_ID = "0ae51e19-07c8-4e4b-bb6d-648ee58410f4"; + private static final ResourceBundle MESSAGES = ResourceBundle.getBundle(LOGIN_MESSAGE_BUNDLE); private static final int AUTHENTICATION_CODE_TIMEOUT_MILLISECONDS = 120 * 1000; + private final Range callbackPortRange; + private final BiFunction + callbackServerProvider; @Getter @Parameter(names = "--help", descriptionKey = "option.help-description", help = true) private boolean help; - private final Range callbackPortRange; - private final BiFunction oAuth20ServiceProvider; - private final Function callbackServerProvider; - public LoginCommand() { this( DEFAULT_CALLBACK_PORTS, - (vcpConfig, callbackUrl) -> - new ServiceBuilder(vcpConfig.getOAuth2ClientId()) - .defaultScope(String.join(" ", SCOPES)) - .callback(callbackUrl.toString()) - .build(MicrosoftAzureActiveDirectory20Api.custom(TENANT_ID)), - url -> + (url, state) -> new OAuth2AuthenticationCodeCallbackHttpServer( - url, AUTHENTICATION_CODE_TIMEOUT_MILLISECONDS)); + url, state, AUTHENTICATION_CODE_TIMEOUT_MILLISECONDS)); } LoginCommand( Range callbackPortRange, - BiFunction oAuth20ServiceProvider, - Function callbackServerProvider) { + BiFunction callbackServerProvider) { this.callbackPortRange = callbackPortRange; - this.oAuth20ServiceProvider = oAuth20ServiceProvider; this.callbackServerProvider = callbackServerProvider; } + private static TokenRequest createTokenRequest( + VcpConfiguration vcpConfiguration, + AuthorizationCode authzCode, + URI callback, + ClientID clientID) { + AuthorizationGrant authzGrant = new AuthorizationCodeGrant(authzCode, callback); + Scope scope = new Scope("offline", "openid"); + + return new TokenRequest( + vcpConfiguration.getOauth2TokenEndpointUri(), clientID, authzGrant, scope); + } + public void login() throws CsCliLoginException, CsCliConfigurationException { if (isHelp()) { System.out.println(StringEscapeUtils.unescapeJava(MESSAGES.getString("detailed-help"))); @@ -100,7 +97,12 @@ public void login() throws CsCliLoginException, CsCliConfigurationException { Configuration configuration = Configuration.getInstance(); List tokens = Lists.newArrayList(); for (VcpConfiguration vcpConfig : configuration.getProviders()) { - Either login = login(vcpConfig, callbackPortRange); + Either login = + login( + vcpConfig, + callbackPortRange, + configuration.isNoSslValidation(), + configuration.getTrustedCertificates()); tokens.add(login.getOrElseThrow(CsCliLoginException::new)); } VcpTokenStore store = VcpTokenStore.builder().tokens(tokens).build(); @@ -108,7 +110,10 @@ public void login() throws CsCliLoginException, CsCliConfigurationException { } private Either login( - VcpConfiguration vcpConfiguration, Range callbackPortCandidates) { + VcpConfiguration vcpConfiguration, + Range callbackPortCandidates, + boolean insecure, + List trustedCertificates) { URI callbackUrl = Try.of( () -> @@ -116,31 +121,54 @@ private Either login( .setPort(callbackPortCandidates.getMinimum()) .build()) .getOrElseThrow(t -> new IllegalStateException(t)); - OAuth20Service oAuth20Service = oAuth20ServiceProvider.apply(vcpConfiguration, callbackUrl); + log.debug("launching callback server on local address {}", callbackUrl); + + // used to compare against the state in the callback handler for CSRF protection + // @see io.carbynestack.cli.login.OAuth2AuthenticationCodeCallbackHttpServer + State state = new State(); + try (OAuth2AuthenticationCodeCallbackHttpServer server = - callbackServerProvider.apply(callbackUrl)) { - URI authorizationUrl = URI.create(oAuth20Service.getAuthorizationUrl()); - Option failed = BrowserLauncher.browse(authorizationUrl); + callbackServerProvider.apply(callbackUrl, state)) { + + ClientID clientID = new ClientID(vcpConfiguration.getOAuth2ClientId()); + URI callback = vcpConfiguration.getOAuth2CallbackUrl(); + Nonce nonce = new Nonce(); + + AuthenticationRequest request = + new AuthenticationRequest.Builder( + new ResponseType("code"), new Scope("openid", "offline"), clientID, callback) + .endpointURI(vcpConfiguration.getOauth2AuthEndpointUri()) + .state(state) + .nonce(nonce) + .build(); + + Option failed = BrowserLauncher.browse(request.toURI()); if (failed.isDefined()) { return Either.left(failed.get()); } + return server - .getCode() + .getAuthorizationCode() .map( code -> Try.of( - () -> - oAuth20Service.getAccessToken( - AccessTokenRequestParams.create(code) - .scope( - String.format( - "api://%s/Cs.Generic", - vcpConfiguration.getOAuth2ClientId()))))) - .mapLeft( - e -> - (AuthenticationError) - e) // Required to help the compiler to get the types sorted out + () -> { + TokenResponse tokenResponse = + sendTokenRequest( + createTokenRequest(vcpConfiguration, code, callback, clientID), + insecure, + trustedCertificates); + if (tokenResponse instanceof TokenErrorResponse) { + throw new CsCliLoginException( + LoginCommandError.FAILED_TO_GET_ACCESS_TOKEN); + } + + OIDCTokenResponse successResponse = + (OIDCTokenResponse) tokenResponse.toSuccessResponse(); + return successResponse.getOIDCTokens(); + })) + .mapLeft(e -> (AuthenticationError) e) .flatMap( t -> t.onFailure(e -> log.error("getting access token failed unexpectedly", e)) @@ -152,11 +180,36 @@ private Either login( if (RangeUtils.getLength(callbackPortCandidates) <= 1) { return Either.left(LoginCommandError.PORT_RANGE_EXHAUSTION); } - return login(vcpConfiguration, RangeUtils.consumeLower(callbackPortCandidates)); + return login( + vcpConfiguration, + RangeUtils.consumeLower(callbackPortCandidates), + insecure, + trustedCertificates); } else { log.error("login failed for unexpected reason", re); return Either.left(LoginCommandError.UNEXPECTED); } } } + + protected TokenResponse sendTokenRequest( + TokenRequest request, boolean insecure, List trustedCertificates) + throws IOException, ParseException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException, CertificateException { + HTTPRequest httpRequest = request.toHTTPRequest(); + OAuthUtil.setSslContextForRequestWithConfiguration(httpRequest, insecure, trustedCertificates); + return OIDCTokenResponseParser.parse(httpRequest.send()); + } + + public enum LoginCommandError implements AuthenticationError { + + /** Something went wrong when retrieving the access token */ + FAILED_TO_GET_ACCESS_TOKEN, + + /** No free port is available for launching the webserver for the callback */ + PORT_RANGE_EXHAUSTION, + + /** An unexpected error condition occurred while performing the login */ + UNEXPECTED + } } diff --git a/src/main/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServer.java b/src/main/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServer.java index 7f3fb6e..2fe1bc4 100644 --- a/src/main/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServer.java +++ b/src/main/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServer.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -9,14 +9,17 @@ import static io.vavr.API.*; import static io.vavr.Predicates.instanceOf; +import com.nimbusds.oauth2.sdk.AuthorizationCode; +import com.nimbusds.oauth2.sdk.id.State; +import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse; +import com.nimbusds.openid.connect.sdk.AuthenticationResponse; +import com.nimbusds.openid.connect.sdk.AuthenticationResponseParser; import io.undertow.Undertow; import io.undertow.util.Headers; import io.vavr.control.Either; -import io.vavr.control.Option; import io.vavr.control.Try; import java.io.Closeable; import java.net.URI; -import java.util.ArrayDeque; import java.util.concurrent.LinkedTransferQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.TransferQueue; @@ -26,57 +29,59 @@ public class OAuth2AuthenticationCodeCallbackHttpServer implements Closeable { public static final long DEFAULT_TIMEOUT_MILLIS = 120L * 1000L; - - public enum CallbackError implements AuthenticationError { - /** The callback request didn't contain the request code. */ - MISSING_AUTHENTICATION_CODE, - - /** Interrupted while waiting for callback to be invoked. */ - INTERRUPTED, - - /** Time out while waiting for callback. */ - TIME_OUT, - - /** Some unexpected error condition occurred fetching the authorization code. */ - UNEXPECTED - } - - private final TransferQueue> queue = new LinkedTransferQueue<>(); + private final TransferQueue> queue = + new LinkedTransferQueue<>(); private final Undertow server; private final long timeout; private boolean transferred; - public OAuth2AuthenticationCodeCallbackHttpServer(URI callbackUrl) { - this(callbackUrl, DEFAULT_TIMEOUT_MILLIS); + public OAuth2AuthenticationCodeCallbackHttpServer(URI callbackUrl, State state) { + this(callbackUrl, state, DEFAULT_TIMEOUT_MILLIS); } - public OAuth2AuthenticationCodeCallbackHttpServer(URI callbackUrl, long timeout) { + public OAuth2AuthenticationCodeCallbackHttpServer(URI callbackUrl, State state, long timeout) { transferred = false; this.timeout = timeout; server = Undertow.builder() .addHttpListener(callbackUrl.getPort(), callbackUrl.getHost()) .setHandler( - exchange -> { + handler -> { synchronized (OAuth2AuthenticationCodeCallbackHttpServer.this) { - Either code = - Option.of( - exchange - .getQueryParameters() - .getOrDefault("code", new ArrayDeque<>()) - .peek()) - .toEither(CallbackError.MISSING_AUTHENTICATION_CODE); - if (!transferred && queue.tryTransfer(code, timeout, TimeUnit.MILLISECONDS)) { - exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); - exchange + + // example + AuthenticationResponse response = + AuthenticationResponseParser.parse( + URI.create(handler.getRequestURL() + "?" + handler.getQueryString())); + + // Check the state to ensure the response is valid (not a CSRF attack) + if (response instanceof AuthenticationErrorResponse + || !response.getState().equals(state)) { + handler.setStatusCode(500); + handler.endExchange(); + return; + } + + // Convert to a successful response to get the access token + var accessToken = response.toSuccessResponse().getAuthorizationCode(); + Either transferElement = + accessToken == null + ? Either.left(CallbackError.MISSING_AUTHENTICATION_CODE) + : Either.right(accessToken); + + // transfer it to the concurrent.TransferQueue to be picked up by the + // getAccessToken method + if (!transferred + && queue.tryTransfer(transferElement, timeout, TimeUnit.MILLISECONDS)) { + handler.getResponseHeaders().put(Headers.CONTENT_TYPE, "text/plain"); + handler .getResponseSender() - .send( - code.fold(Object::toString, c -> "Authentication code received.") - + "Please return to CLI."); + .send("Authorization code received. You can close this window now."); + transferred = true; } else { - exchange.setStatusCode(500); - exchange.endExchange(); + handler.setStatusCode(500); + handler.endExchange(); } } }) @@ -84,11 +89,14 @@ public OAuth2AuthenticationCodeCallbackHttpServer(URI callbackUrl, long timeout) server.start(); } - public Either getCode() { + public Either getAuthorizationCode() { return Try.of( () -> { - Either r = queue.poll(timeout, TimeUnit.MILLISECONDS); - return r == null ? Either.left(CallbackError.TIME_OUT) : r; + Either r = + queue.poll(timeout, TimeUnit.MILLISECONDS); + return r == null + ? Either.left(CallbackError.TIME_OUT) + : r; }) .onFailure(e -> log.error("failed fetching authorization code", e)) .getOrElseGet( @@ -107,4 +115,18 @@ public void close() { server.getWorker().shutdownNow(); server.stop(); } + + public enum CallbackError implements AuthenticationError { + /** The callback request didn't contain the request code. */ + MISSING_AUTHENTICATION_CODE, + + /** Interrupted while waiting for callback to be invoked. */ + INTERRUPTED, + + /** Time out while waiting for callback. */ + TIME_OUT, + + /** Some unexpected error condition occurred fetching the authorization code. */ + UNEXPECTED + } } diff --git a/src/main/java/io/carbynestack/cli/login/VcpToken.java b/src/main/java/io/carbynestack/cli/login/VcpToken.java index 1e57549..957abaf 100644 --- a/src/main/java/io/carbynestack/cli/login/VcpToken.java +++ b/src/main/java/io/carbynestack/cli/login/VcpToken.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -7,7 +7,7 @@ package io.carbynestack.cli.login; import com.fasterxml.jackson.annotation.JsonIgnore; -import com.github.scribejava.core.model.OAuth2AccessToken; +import com.nimbusds.openid.connect.sdk.token.OIDCTokens; import java.net.URI; import java.time.temporal.ChronoUnit; import java.util.Date; @@ -18,23 +18,26 @@ @AllArgsConstructor public class VcpToken { - public static VcpToken from(Date created, URI vcpBaseUrl, OAuth2AccessToken token) { + String vcpBaseUrl; + String accessToken; + String idToken; + String refreshToken; + Date expires; + + public static VcpToken from(Date created, URI vcpBaseUrl, OIDCTokens tokens) { return new VcpToken( vcpBaseUrl.toString(), - token.getAccessToken(), - token.getRefreshToken(), - Date.from(created.toInstant().plus(token.getExpiresIn(), ChronoUnit.SECONDS))); + tokens.getAccessToken().getValue(), + tokens.getIDTokenString(), + tokens.getRefreshToken().getValue(), + Date.from( + created.toInstant().plus(tokens.getAccessToken().getLifetime(), ChronoUnit.SECONDS))); } - public static VcpToken from(URI vcpBaseUrl, OAuth2AccessToken token) { - return from(new Date(), vcpBaseUrl, token); + public static VcpToken from(URI vcpBaseUrl, OIDCTokens tokens) { + return from(new Date(), vcpBaseUrl, tokens); } - String vcpBaseUrl; - String accessToken; - String refreshToken; - Date expires; - @JsonIgnore public boolean isExpired() { return new Date().after(expires); diff --git a/src/main/java/io/carbynestack/cli/login/VcpTokenStore.java b/src/main/java/io/carbynestack/cli/login/VcpTokenStore.java index d398465..fcdc4e4 100644 --- a/src/main/java/io/carbynestack/cli/login/VcpTokenStore.java +++ b/src/main/java/io/carbynestack/cli/login/VcpTokenStore.java @@ -1,22 +1,22 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 */ package io.carbynestack.cli.login; -import static io.carbynestack.cli.login.LoginCommand.*; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonIgnoreType; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.scribejava.apis.MicrosoftAzureActiveDirectory20Api; -import com.github.scribejava.core.builder.ServiceBuilder; -import com.github.scribejava.core.oauth.OAuth20Service; import com.google.common.collect.Lists; +import com.nimbusds.oauth2.sdk.*; +import com.nimbusds.oauth2.sdk.http.HTTPRequest; +import com.nimbusds.oauth2.sdk.id.ClientID; +import com.nimbusds.oauth2.sdk.token.RefreshToken; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; import io.carbynestack.cli.configuration.Configuration; import io.carbynestack.cli.configuration.VcpConfiguration; +import io.carbynestack.cli.exceptions.CsCliRunnerException; +import io.carbynestack.cli.util.OAuthUtil; import io.vavr.Tuple2; import io.vavr.control.Either; import io.vavr.control.Option; @@ -24,10 +24,13 @@ import java.io.*; import java.net.URI; import java.nio.file.Path; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; import java.time.Duration; import java.time.Instant; import java.util.*; -import java.util.function.Function; import java.util.stream.Collectors; import lombok.*; import lombok.extern.slf4j.Slf4j; @@ -38,36 +41,19 @@ @Builder(builderClassName = "VcpTokenStoreBuilder", toBuilder = true) public class VcpTokenStore { - public interface VcpTokenStoreError extends AuthenticationError {} - - public enum VcpTokenStoreErrors implements VcpTokenStoreError { - - /** The token store could not be read */ - READING_TOKEN_STORE_FAILED, - - /** The token store could not be written. */ - PERSISTING_TOKEN_STORE_FAILED, + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + private static Option customDefaultLocation = Option.none(); - /** The VCP configuration could not be fetched. */ - VCP_CONFIGURATION_UNAVAILABLE, + @Singular List tokens; - /** Refreshing a token failed */ - REFRESHING_TOKEN_FAILED + public VcpTokenStore() { + this.tokens = Lists.newArrayList(); } - @Value - @RequiredArgsConstructor(staticName = "of") - public static class ByTokenError implements VcpTokenStoreError { - @NonNull HashMap errors; + public VcpTokenStore(List tokens) { + this.tokens = tokens; } - private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); - private static Option customDefaultLocation = Option.none(); - private static final OAuth2ServiceProvider DEFAULT_OAUTH20_SERVICE_PROVIDER = - c -> - new ServiceBuilder(c.getOAuth2ClientId()) - .build(MicrosoftAzureActiveDirectory20Api.custom(TENANT_ID)); - public static Path getDefaultLocation() { return customDefaultLocation.getOrElse( FileUtils.getUserDirectory().toPath().resolve(".cs/access-tokens.json")); @@ -85,7 +71,9 @@ public static Either load(Reader r, boolean r .onFailure(t -> log.error("reading token store failed", t)) .toEither() .mapLeft(t -> VcpTokenStoreErrors.READING_TOKEN_STORE_FAILED); - return refresh ? notRefreshedStore.flatMap(VcpTokenStore::refresh) : notRefreshedStore; + return refresh + ? notRefreshedStore.flatMap(VcpTokenStore::refresh).peek(VcpTokenStore::persist) + : notRefreshedStore; } public static boolean exists() { @@ -102,33 +90,21 @@ public static Either load(boolean refresh) { } } - /* - * This is extended by Lombok. Required to make initialization work for Jackson deserialization. - */ - public static class VcpTokenStoreBuilder { - private OAuth2ServiceProvider oAuth20ServiceProvider = DEFAULT_OAUTH20_SERVICE_PROVIDER; - } - - /* - * Used to exclude oAuth20ServiceProvider from JSON serialization as @JsonIgnore does (for some reason) not work - * together with @Value class. - */ - @JsonIgnoreType - public interface OAuth2ServiceProvider extends Function {} - - @Singular List tokens; - - @JsonIgnore @EqualsAndHashCode.Exclude OAuth2ServiceProvider oAuth20ServiceProvider; - - public VcpTokenStore() { - this.tokens = Lists.newArrayList(); - this.oAuth20ServiceProvider = DEFAULT_OAUTH20_SERVICE_PROVIDER; - } - - public VcpTokenStore(List tokens, OAuth2ServiceProvider oAuth20ServiceProvider) { - this.tokens = tokens; - this.oAuth20ServiceProvider = - oAuth20ServiceProvider == null ? DEFAULT_OAUTH20_SERVICE_PROVIDER : oAuth20ServiceProvider; + OIDCTokenResponse sendRefreshToken( + VcpToken token, VcpConfiguration c, boolean insecure, List trustedCertificates) + throws ParseException, IOException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException, CertificateException { + + ClientID clientID = new ClientID(c.getOAuth2ClientId()); + AuthorizationGrant refreshTokenGrant = + new RefreshTokenGrant(new RefreshToken(token.getRefreshToken())); + Scope authScope = new Scope("offline", "openid"); + + TokenRequest request = + new TokenRequest(c.getOauth2TokenEndpointUri(), clientID, refreshTokenGrant, authScope); + HTTPRequest httpRequest = request.toHTTPRequest(); + OAuthUtil.setSslContextForRequestWithConfiguration(httpRequest, insecure, trustedCertificates); + return OIDCTokenResponse.parse(httpRequest.send()); } public Either persist(Writer w) { @@ -201,13 +177,23 @@ private Either refresh( Date expiration = token.getExpires(); Duration stillValidFor = Duration.between(Instant.now(), expiration.toInstant()); if (stillValidFor.toHours() < 1) { + log.debug("refreshing token for VCP with base URL {}", token.getVcpBaseUrl()); - OAuth20Service oAuth20Service = getOAuth20ServiceProvider().apply(c); return Try.of( - () -> - oAuth20Service.refreshAccessToken( - token.getRefreshToken(), - String.format("api://%s/Cs.Generic", c.getOAuth2ClientId()))) + () -> { + var oidcTokenResponse = + sendRefreshToken( + token, + c, + configuration.isNoSslValidation(), + configuration.getTrustedCertificates()); + if (oidcTokenResponse.indicatesSuccess()) { + return oidcTokenResponse.toSuccessResponse().getOIDCTokens(); + } else { + throw new CsCliRunnerException( + oidcTokenResponse.toErrorResponse().getErrorObject().toString()); + } + }) .onFailure( t -> log.error( @@ -217,11 +203,34 @@ private Either refresh( t)) .toEither() .bimap( - t -> (VcpTokenStoreError) VcpTokenStoreErrors.REFRESHING_TOKEN_FAILED, + t -> VcpTokenStoreErrors.REFRESHING_TOKEN_FAILED, t -> VcpToken.from(c.getBaseUrl(), t)); } else { return Either.right(token); } }); } + + public enum VcpTokenStoreErrors implements VcpTokenStoreError { + + /** The token store could not be read */ + READING_TOKEN_STORE_FAILED, + + /** The token store could not be written. */ + PERSISTING_TOKEN_STORE_FAILED, + + /** The VCP configuration could not be fetched. */ + VCP_CONFIGURATION_UNAVAILABLE, + + /** Refreshing a token failed */ + REFRESHING_TOKEN_FAILED + } + + public interface VcpTokenStoreError extends AuthenticationError {} + + @Value + @RequiredArgsConstructor(staticName = "of") + public static class ByTokenError implements VcpTokenStoreError { + @NonNull HashMap errors; + } } diff --git a/src/main/java/io/carbynestack/cli/util/KeyStoreUtil.java b/src/main/java/io/carbynestack/cli/util/KeyStoreUtil.java deleted file mode 100644 index 0ac3055..0000000 --- a/src/main/java/io/carbynestack/cli/util/KeyStoreUtil.java +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright (c) 2021 - for information on the respective copyright owner - * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. - * - * SPDX-License-Identifier: Apache-2.0 - */ - -package io.carbynestack.cli.util; - -import io.carbynestack.cli.exceptions.CsCliRunnerException; -import io.vavr.control.Option; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; -import java.io.IOException; -import java.nio.file.Path; -import java.security.KeyStore; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.cert.CertificateException; -import java.security.cert.CertificateFactory; -import java.security.cert.X509Certificate; -import java.util.List; - -public class KeyStoreUtil { - public static Option tempKeyStoreForPems(List certs) throws CsCliRunnerException { - if (certs.isEmpty()) { - return Option.none(); - } - try { - KeyStore tmpKeyStore = KeyStore.getInstance("JKS"); - CertificateFactory certificateFactory = CertificateFactory.getInstance("X509"); - tmpKeyStore.load(null); - for (Path certificate : certs) { - X509Certificate x509Certificate = - (X509Certificate) - certificateFactory.generateCertificate(new FileInputStream(certificate.toFile())); - tmpKeyStore.setCertificateEntry( - x509Certificate.getSubjectX500Principal().getName(), x509Certificate); - } - File tempFile = File.createTempFile("cs_keystore", ".jks"); - try (FileOutputStream fos = new FileOutputStream(tempFile)) { - tmpKeyStore.store(fos, "".toCharArray()); - } - tempFile.deleteOnExit(); - return Option.some(tempFile); - } catch (KeyStoreException | CertificateException | IOException | NoSuchAlgorithmException e) { - throw new CsCliRunnerException("Failed to generate temporary keystore.", e); - } - } -} diff --git a/src/main/java/io/carbynestack/cli/util/OAuthUtil.java b/src/main/java/io/carbynestack/cli/util/OAuthUtil.java new file mode 100644 index 0000000..bc0334b --- /dev/null +++ b/src/main/java/io/carbynestack/cli/util/OAuthUtil.java @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2024 - for information on the respective copyright owner + * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.carbynestack.cli.util; + +import static java.util.stream.Collectors.toList; + +import com.nimbusds.oauth2.sdk.http.HTTPRequest; +import io.carbynestack.httpclient.CompositeX509TrustManager; +import io.carbynestack.httpclient.ExtendedSSLContextBuilder; +import io.carbynestack.httpclient.X509TrustManagerUtils; +import java.io.File; +import java.io.IOException; +import java.nio.file.Path; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Stream; +import javax.net.ssl.SSLContext; +import javax.net.ssl.X509TrustManager; +import org.apache.http.conn.ssl.NoopHostnameVerifier; +import org.apache.http.conn.ssl.TrustAllStrategy; +import org.apache.http.ssl.SSLContextBuilder; + +public class OAuthUtil { + private OAuthUtil() {} + + public static void setSslContextForRequestWithConfiguration( + HTTPRequest httpRequest, boolean insecure, List trustedCertificates) + throws NoSuchAlgorithmException, KeyStoreException, KeyManagementException, + CertificateException, IOException { + if (insecure) { + SSLContext sslContext = + new SSLContextBuilder().loadTrustMaterial(null, new TrustAllStrategy()).build(); + httpRequest.setSSLSocketFactory(sslContext.getSocketFactory()); + httpRequest.setHostnameVerifier(new NoopHostnameVerifier()); + } else if (trustedCertificates != null && !trustedCertificates.isEmpty()) { + List certFiles = trustedCertificates.stream().map(Path::toFile).collect(toList()); + List> custom = + Collections.singletonList(X509TrustManagerUtils.getX509TrustManager(certFiles)); + List allTrustManagers = + Stream.concat( + custom.stream(), Stream.of(X509TrustManagerUtils.getDefaultX509TrustManager())) + .filter(Optional::isPresent) + .map(Optional::get) + .collect(toList()); + SSLContextBuilder sslContextBuilder = + ExtendedSSLContextBuilder.create(new CompositeX509TrustManager(allTrustManagers)); + httpRequest.setSSLSocketFactory(sslContextBuilder.build().getSocketFactory()); + } + } +} diff --git a/src/main/resources/ConfigurationMessageBundle.properties b/src/main/resources/ConfigurationMessageBundle.properties index c8aaa1e..c4aa9d7 100644 --- a/src/main/resources/ConfigurationMessageBundle.properties +++ b/src/main/resources/ConfigurationMessageBundle.properties @@ -1,5 +1,5 @@ # -# Copyright (c) 2021 - for information on the respective copyright owner +# Copyright (c) 2021-2024 - for information on the respective copyright owner # see the NOTICE file and/or the repository https://github.com/carbynestack/cli. # # SPDX-License-Identifier: Apache-2.0 @@ -24,12 +24,14 @@ configuration.request.vcp.castor-service-url=Castor Service URL [{0}]: configuration.request.vcp.ephemeral-service-url=Ephemeral Service URL [{0}]: configuration.request.vcp.oauth2-client-id=OAuth2 Client Identifier [{0}]: configuration.request.vcp.oauth2-callback-url=OAuth2 Callback URL [{0}]: +configuration.request.vcp.oauth2-auth-endpoint-uri=OAuth2 Authorization Endpoint URI [{0}]: +configuration.request.vcp.oauth2-token-endpoint-uri=OAuth2 Token Endpoint URI [{0}]: configuration.invalid-input.number-of-players=Invalid number of providers ({0}). Number of providers must be a positive integer >= 2. configuration.finalize.request.complete=Store configuration? (yes/no) [{0}]: -configuration.finalize.invalid-input.request-complete:Invalid input - please try again [{0}]: -configuration.finalize.failed.invalid-input-request-complete:Invalid user decision on finalization \"{0}\". -configuration.finalize.failed.creating-config-directory:Failed creating the configuration directory. -configuration.finalize.failed.writing-configuration:Failed writing the configuration to config file. +configuration.finalize.invalid-input.request-complete=Invalid input - please try again [{0}]: +configuration.finalize.failed.invalid-input-request-complete=Invalid user decision on finalization \"{0}\". +configuration.finalize.failed.creating-config-directory=Failed creating the configuration directory. +configuration.finalize.failed.writing-configuration=Failed writing the configuration to config file. configuration.failed=Error while performing configuration configuration.access.invalid-provider-id=Invalid provider ID #{0} failure.not-configured=No configuration found. Please call \"{0} {1}\" first! @@ -49,6 +51,8 @@ The following environment variables can be used to adapt the configuration witho - CS_VCP_{n}_EPHEMERAL_URL* \t Ephemeral Service URL for the provider with ID \"{n}\" \n \ - CS_VCP_{n}_OAUTH2_CLIENT_ID * \t OAuth2 client identifier for the provider with ID \"{n}\" \n \ - CS_VCP_{n}_OAUTH2_CALLBACK_URL * \t OAuth2 callback URL for the provider with ID \"{n}\" \n \ +- CS_VCP_{n}_OAUTH2_AUTH_ENDPOINT_URI * \t OAuth2 authorization endpoint URI for the provider with ID \"{n}\" \n \ +- CS_VCP_{n}_OAUTH2_TOKEN_ENDPOINT_URI * \t OAuth2 token endpoint URI for the provider with ID \"{n}\" \n \ \n \ * Please be aware, that only providers defined in the default configuration can be adapted using environment variables. It is not possible to add additional or remove existing providers. \n \ ** This variable is used during the configuration process only. diff --git a/src/test/java/io/carbynestack/cli/TemporaryConfiguration.java b/src/test/java/io/carbynestack/cli/TemporaryConfiguration.java index bcc28ee..ea8dd6f 100644 --- a/src/test/java/io/carbynestack/cli/TemporaryConfiguration.java +++ b/src/test/java/io/carbynestack/cli/TemporaryConfiguration.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -22,7 +22,6 @@ import java.util.function.Function; import java.util.function.Supplier; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.lang3.RandomStringUtils; import org.junit.rules.TemporaryFolder; @Slf4j @@ -62,12 +61,7 @@ protected void before() throws Throwable { VcpTokenStore.setDefaultLocation(Option.of(accessTokensFile.toPath())); VcpTokenStore.VcpTokenStoreBuilder builder = VcpTokenStore.builder(); Lists.newArrayList(configuration.getProviders()) - .forEach( - p -> - builder.token( - VcpToken.from( - p.getBaseUrl(), - TokenUtils.createToken(RandomStringUtils.randomAlphabetic(10))))); + .forEach(p -> builder.token(VcpToken.from(p.getBaseUrl(), TokenUtils.createToken()))); VcpTokenStore s = builder.build(); s.persist(); } diff --git a/src/test/java/io/carbynestack/cli/configuration/ConfigurationUtil.java b/src/test/java/io/carbynestack/cli/configuration/ConfigurationUtil.java index 9192781..86c906b 100644 --- a/src/test/java/io/carbynestack/cli/configuration/ConfigurationUtil.java +++ b/src/test/java/io/carbynestack/cli/configuration/ConfigurationUtil.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -14,8 +14,8 @@ public class ConfigurationUtil { - private static final String VCP_1_BASE_URL = "http://apollo.example.com"; - private static final String VCP_2_BASE_URL = "http://starbuck.example.com"; + private static final String VCP_1_BASE_URL = "https://apollo.example.com"; + private static final String VCP_2_BASE_URL = "https://starbuck.example.com"; @SneakyThrows public static Configuration getConfiguration(String vcp1BaseUrl, String vcp2BaseUrl) { @@ -28,6 +28,10 @@ public static Configuration getConfiguration(String vcp1BaseUrl, String vcp2Base configuration.getProvider(1).ephemeralServiceUrl = URI.create(String.format("%s", vcp1BaseUrl)); configuration.getProvider(1).oAuth2clientId = UUID.randomUUID().toString(); configuration.getProvider(1).oAuth2CallbackUrl = URI.create("http://localhost/vcp-1"); + configuration.getProvider(1).oAuth2AuthEndpointUri = + URI.create(String.format("%s/auth2/auth", vcp1BaseUrl)); + configuration.getProvider(1).oAuth2TokenEndpointUri = + URI.create(String.format("%s/auth2/token", vcp1BaseUrl)); configuration.getProvider(2).baseUrl = URI.create(VCP_2_BASE_URL); configuration.getProvider(2).amphoraServiceUri = new AmphoraServiceUri(String.format("%s/amphora", vcp2BaseUrl)); @@ -36,6 +40,10 @@ public static Configuration getConfiguration(String vcp1BaseUrl, String vcp2Base configuration.getProvider(2).ephemeralServiceUrl = URI.create(String.format("%s", vcp2BaseUrl)); configuration.getProvider(2).oAuth2clientId = UUID.randomUUID().toString(); configuration.getProvider(2).oAuth2CallbackUrl = URI.create("http://localhost/vcp-2"); + configuration.getProvider(2).oAuth2AuthEndpointUri = + URI.create(String.format("%s/auth2/auth", vcp2BaseUrl)); + configuration.getProvider(2).oAuth2TokenEndpointUri = + URI.create(String.format("%s/auth2/token", vcp2BaseUrl)); return configuration; } diff --git a/src/test/java/io/carbynestack/cli/configuration/VcpConfigurationTest.java b/src/test/java/io/carbynestack/cli/configuration/VcpConfigurationTest.java index 6bd72f2..b38263b 100644 --- a/src/test/java/io/carbynestack/cli/configuration/VcpConfigurationTest.java +++ b/src/test/java/io/carbynestack/cli/configuration/VcpConfigurationTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -29,10 +29,9 @@ public class VcpConfigurationTest { private static final ResourceBundle MESSAGES = ResourceBundle.getBundle(CONFIGURATION_MESSAGE_BUNDLE); - + @Rule public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); @Rule public EnvironmentVariables environmentVariables = new EnvironmentVariables(); @Rule public TextFromStandardInputStream systemInMock = emptyStandardInputStream(); - @Rule public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); @Test public void givenEnvVariableForVcp1AmphoraService_whenGetAmphoraUrl_thenReturnEnvVariableValue() @@ -83,6 +82,10 @@ public void givenEnvVariableForVcp1CastorService_whenGetCastorUrl_thenReturnEnvV String.format("http://%s", RandomStringUtils.randomAlphanumeric(15)); String expectedOAuth2CliendId = UUID.randomUUID().toString(); String expectedOAuth2CallbackUrl = "http://localhost/vcp-1"; + String expectedOAuth2EndpointUri = + String.format("http://%s/oauth2/auth", RandomStringUtils.randomAlphanumeric(15)); + String expectedOAuth2TokenUri = + String.format("http://%s/oauth2/token", RandomStringUtils.randomAlphanumeric(15)); VcpConfiguration vcpConfiguration = new VcpConfiguration(1); systemInMock.provideLines( "", @@ -90,6 +93,8 @@ public void givenEnvVariableForVcp1CastorService_whenGetCastorUrl_thenReturnEnvV expectedCasorUrl, expectedEphemeralUrl, expectedOAuth2CliendId, + expectedOAuth2EndpointUri, + expectedOAuth2TokenUri, expectedOAuth2CallbackUrl); vcpConfiguration.configure(); Assert.assertNull(vcpConfiguration.baseUrl); @@ -118,6 +123,7 @@ public void givenEnvVariableForVcp1CastorService_whenGetCastorUrl_thenReturnEnvV CoreMatchers.containsString( MessageFormat.format( MESSAGES.getString("configuration.request.vcp.oauth2-callback-url"), ""))); + assertEquals( new AmphoraServiceUri(expectedAmphoraUrl), vcpConfiguration.getAmphoraServiceUri()); assertEquals(new CastorServiceUri(expectedCasorUrl), vcpConfiguration.getCastorServiceUri()); diff --git a/src/test/java/io/carbynestack/cli/login/LoginCommandTest.java b/src/test/java/io/carbynestack/cli/login/LoginCommandTest.java index 463ac78..cb47755 100644 --- a/src/test/java/io/carbynestack/cli/login/LoginCommandTest.java +++ b/src/test/java/io/carbynestack/cli/login/LoginCommandTest.java @@ -1,24 +1,26 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 */ package io.carbynestack.cli.login; -import static io.carbynestack.cli.login.BrowserLauncher.*; -import static io.carbynestack.cli.login.BrowserLauncher.BrowserLaunchError.*; -import static io.carbynestack.cli.login.LoginCommand.*; -import static io.carbynestack.cli.login.VcpTokenStore.*; +import static io.carbynestack.cli.login.BrowserLauncher.BrowserLaunchError.NOT_SUPPORTED; +import static io.carbynestack.cli.login.BrowserLauncher.browse; +import static io.carbynestack.cli.login.LoginCommand.DEFAULT_CALLBACK_PORTS; +import static io.carbynestack.cli.login.LoginCommand.LoginCommandError; +import static io.carbynestack.cli.login.VcpTokenStore.VcpTokenStoreError; +import static io.carbynestack.cli.login.VcpTokenStore.load; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.*; -import com.github.scribejava.core.model.OAuth2AccessToken; -import com.github.scribejava.core.oauth.AccessTokenRequestParams; -import com.github.scribejava.core.oauth.OAuth20Service; +import com.nimbusds.oauth2.sdk.AuthorizationCode; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; +import com.nimbusds.openid.connect.sdk.token.OIDCTokens; import io.carbynestack.cli.TemporaryConfiguration; import io.carbynestack.cli.util.TokenUtils; import io.vavr.control.Either; @@ -32,144 +34,154 @@ import org.junit.Rule; import org.junit.Test; import org.junit.contrib.java.lang.system.SystemOutRule; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.MockedStatic; +import org.mockito.Mockito; -@RunWith(PowerMockRunner.class) -@PrepareForTest({BrowserLauncher.class}) public class LoginCommandTest { @Rule public final TemporaryConfiguration temporaryConfiguration = new TemporaryConfiguration(); @Rule public final SystemOutRule systemOutRule = new SystemOutRule().enableLog(); - private OAuth20Service oAuth20Service; - private OAuth2AccessToken token; + private OIDCTokens oidcTokens; @Before - public void configureMocks() throws Exception { - PowerMockito.mockStatic(BrowserLauncher.class); - oAuth20Service = mock(OAuth20Service.class); - token = TokenUtils.createToken("test"); - doReturn(token).when(oAuth20Service).getAccessToken(any(AccessTokenRequestParams.class)); + public void configureMocks() { + oidcTokens = TokenUtils.createToken(); } @Test public void whenLogin_thenStoreHasBeenCreated() throws Exception { - doReturn("http://authorize.test.com").when(oAuth20Service).getAuthorizationUrl(); - when(browse(any())).thenReturn(Option.none()); - OAuth2AuthenticationCodeCallbackHttpServer callbackServer = - mock(OAuth2AuthenticationCodeCallbackHttpServer.class); - doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))).when(callbackServer).getCode(); - LoginCommand command = - new LoginCommand( - DEFAULT_CALLBACK_PORTS, (cfg, url) -> oAuth20Service, cfg -> callbackServer); - command.login(); - Either store = load(false); - assertThat("store has not been created", store.isRight()); - for (VcpToken t : store.get().getTokens()) { - assertEquals( - "stored access token does not equal expected token", - token.getAccessToken(), - t.getAccessToken()); + try (MockedStatic ms = mockStatic(BrowserLauncher.class)) { + ms.when(() -> browse(any())).thenReturn(Option.none()); + OAuth2AuthenticationCodeCallbackHttpServer callbackServer = + mock(OAuth2AuthenticationCodeCallbackHttpServer.class); + doReturn(Either.right(new AuthorizationCode())).when(callbackServer).getAuthorizationCode(); + + LoginCommand command = + spy(new LoginCommand(DEFAULT_CALLBACK_PORTS, (url, state) -> callbackServer)); + doReturn(new OIDCTokenResponse(oidcTokens)) + .when(command) + .sendTokenRequest(Mockito.any(), anyBoolean(), anyList()); + + command.login(); + Either store = load(false); + assertThat("store has not been created", store.isRight()); + for (VcpToken t : store.get().getTokens()) { + assertEquals( + "stored access token does not equal expected token", + oidcTokens.getAccessToken().getValue(), + t.getAccessToken()); + } } } @Test public void givenLaunchingBrowserFails_whenLogin_thenThrows() throws Exception { - doReturn("http://authorize.test.com").when(oAuth20Service).getAuthorizationUrl(); - when(browse(any())).thenReturn(Option.some(NOT_SUPPORTED)); - OAuth2AuthenticationCodeCallbackHttpServer callbackServer = - mock(OAuth2AuthenticationCodeCallbackHttpServer.class); - doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))).when(callbackServer).getCode(); - LoginCommand command = - new LoginCommand( - DEFAULT_CALLBACK_PORTS, (cfg, url) -> oAuth20Service, cfg -> callbackServer); - try { - command.login(); - fail("expected exception has not been thrown"); - } catch (CsCliLoginException scle) { - assertEquals("unexpected error returned", NOT_SUPPORTED, scle.getAuthenticationError()); + try (MockedStatic ms = mockStatic(BrowserLauncher.class)) { + ms.when(() -> browse(any())).thenReturn(Option.some(NOT_SUPPORTED)); + OAuth2AuthenticationCodeCallbackHttpServer callbackServer = + mock(OAuth2AuthenticationCodeCallbackHttpServer.class); + doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))) + .when(callbackServer) + .getAuthorizationCode(); + LoginCommand command = + new LoginCommand(DEFAULT_CALLBACK_PORTS, (cfg, state) -> callbackServer); + try { + command.login(); + fail("expected exception has not been thrown"); + } catch (CsCliLoginException scle) { + assertEquals("unexpected error returned", NOT_SUPPORTED, scle.getAuthenticationError()); + } } } @Test public void givenPortIsInUse_whenLogin_thenSucceedOnNextPort() throws Exception { - doReturn("http://authorize.test.com").when(oAuth20Service).getAuthorizationUrl(); - when(browse(any())).thenReturn(Option.none()); - OAuth2AuthenticationCodeCallbackHttpServer callbackServer = - mock(OAuth2AuthenticationCodeCallbackHttpServer.class); - doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))).when(callbackServer).getCode(); - AtomicInteger attempt = new AtomicInteger(0); - int rounds = 5; - LoginCommand command = - new LoginCommand( - DEFAULT_CALLBACK_PORTS, - (cfg, url) -> oAuth20Service, - cfg -> { - if (attempt.getAndAdd(1) < rounds) { - throw new RuntimeException(new BindException()); - } else { - return callbackServer; - } - }); - command.login(); - assertEquals("not enough attempts detected", rounds + 2, attempt.get()); + try (MockedStatic ms = mockStatic(BrowserLauncher.class)) { + ms.when(() -> browse(any())).thenReturn(Option.none()); + OAuth2AuthenticationCodeCallbackHttpServer callbackServer = + mock(OAuth2AuthenticationCodeCallbackHttpServer.class); + doReturn(Either.right(new AuthorizationCode())).when(callbackServer).getAuthorizationCode(); + AtomicInteger attempt = new AtomicInteger(0); + int rounds = 5; + LoginCommand command = + spy( + new LoginCommand( + DEFAULT_CALLBACK_PORTS, + (cfg, state) -> { + if (attempt.getAndAdd(1) < rounds) { + throw new RuntimeException(new BindException()); + } else { + return callbackServer; + } + })); + doReturn(new OIDCTokenResponse(oidcTokens)) + .when(command) + .sendTokenRequest(Mockito.any(), anyBoolean(), anyList()); + + command.login(); + assertEquals("not enough attempts detected", rounds + 2, attempt.get()); + } } @Test public void givenAllPortsAreInUse_whenLogin_thenThrow() throws Exception { - doReturn("http://authorize.test.com").when(oAuth20Service).getAuthorizationUrl(); - when(browse(any())).thenReturn(Option.none()); - OAuth2AuthenticationCodeCallbackHttpServer callbackServer = - mock(OAuth2AuthenticationCodeCallbackHttpServer.class); - doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))).when(callbackServer).getCode(); - int basePort = 32768; - Range portRange = Range.between(basePort, basePort + 7); - AtomicInteger attempts = new AtomicInteger(0); - LoginCommand command = - new LoginCommand( - portRange, - (cfg, url) -> oAuth20Service, - cfg -> { - attempts.getAndIncrement(); - throw new RuntimeException(new BindException()); - }); - try { - command.login(); - fail("expected exception has not been thrown"); - } catch (CsCliLoginException scle) { - assertEquals( - "unexpected error returned", - LoginCommandError.PORT_RANGE_EXHAUSTION, - scle.getAuthenticationError()); - assertEquals("wrong number of attempts", RangeUtils.getLength(portRange), attempts.get()); + try (MockedStatic ms = mockStatic(BrowserLauncher.class)) { + ms.when(() -> browse(any())).thenReturn(Option.none()); + OAuth2AuthenticationCodeCallbackHttpServer callbackServer = + mock(OAuth2AuthenticationCodeCallbackHttpServer.class); + doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))) + .when(callbackServer) + .getAuthorizationCode(); + int basePort = 32768; + Range portRange = Range.between(basePort, basePort + 7); + AtomicInteger attempts = new AtomicInteger(0); + LoginCommand command = + new LoginCommand( + portRange, + (cfg, state) -> { + attempts.getAndIncrement(); + throw new RuntimeException(new BindException()); + }); + try { + command.login(); + fail("expected exception has not been thrown"); + } catch (CsCliLoginException scle) { + assertEquals( + "unexpected error returned", + LoginCommandError.PORT_RANGE_EXHAUSTION, + scle.getAuthenticationError()); + assertEquals("wrong number of attempts", RangeUtils.getLength(portRange), attempts.get()); + } } } @Test public void givenRuntimeExceptionDuringCallbackServerCreation_whenLogin_thenThrow() throws Exception { - doReturn("http://authorize.test.com").when(oAuth20Service).getAuthorizationUrl(); - when(browse(any())).thenReturn(Option.none()); - OAuth2AuthenticationCodeCallbackHttpServer callbackServer = - mock(OAuth2AuthenticationCodeCallbackHttpServer.class); - doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))).when(callbackServer).getCode(); - LoginCommand command = - new LoginCommand( - DEFAULT_CALLBACK_PORTS, - (cfg, url) -> oAuth20Service, - cfg -> { - throw new RuntimeException(new SocketException()); - }); - try { - command.login(); - fail("expected exception has not been thrown"); - } catch (CsCliLoginException scle) { - assertEquals( - "unexpected error returned", LoginCommandError.UNEXPECTED, scle.getAuthenticationError()); + try (MockedStatic ms = mockStatic(BrowserLauncher.class)) { + ms.when(() -> browse(any())).thenReturn(Option.none()); + OAuth2AuthenticationCodeCallbackHttpServer callbackServer = + mock(OAuth2AuthenticationCodeCallbackHttpServer.class); + doReturn(Either.right(RandomStringUtils.randomAlphanumeric(10))) + .when(callbackServer) + .getAuthorizationCode(); + LoginCommand command = + new LoginCommand( + DEFAULT_CALLBACK_PORTS, + (cfg, state) -> { + throw new RuntimeException(new SocketException()); + }); + try { + command.login(); + fail("expected exception has not been thrown"); + } catch (CsCliLoginException scle) { + assertEquals( + "unexpected error returned", + LoginCommandError.UNEXPECTED, + scle.getAuthenticationError()); + } } } } diff --git a/src/test/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServerTest.java b/src/test/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServerTest.java index eea50d7..c708691 100644 --- a/src/test/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServerTest.java +++ b/src/test/java/io/carbynestack/cli/login/OAuth2AuthenticationCodeCallbackHttpServerTest.java @@ -1,17 +1,19 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 */ package io.carbynestack.cli.login; -import static io.carbynestack.cli.login.OAuth2AuthenticationCodeCallbackHttpServer.*; -import static io.carbynestack.cli.login.OAuth2AuthenticationCodeCallbackHttpServer.CallbackError.*; +import static io.carbynestack.cli.login.OAuth2AuthenticationCodeCallbackHttpServer.CallbackError; +import static io.carbynestack.cli.login.OAuth2AuthenticationCodeCallbackHttpServer.CallbackError.MISSING_AUTHENTICATION_CODE; +import static io.carbynestack.cli.login.OAuth2AuthenticationCodeCallbackHttpServer.CallbackError.TIME_OUT; import static org.hamcrest.MatcherAssert.assertThat; -import static org.junit.Assert.*; import static org.junit.Assert.assertEquals; +import com.nimbusds.oauth2.sdk.AuthorizationCode; +import com.nimbusds.oauth2.sdk.id.State; import io.vavr.control.Either; import io.vavr.control.Option; import io.vavr.control.Try; @@ -24,6 +26,7 @@ import org.apache.http.client.methods.HttpGet; import org.apache.http.client.utils.URIBuilder; import org.apache.http.impl.client.HttpClients; +import org.junit.Before; import org.junit.Test; public class OAuth2AuthenticationCodeCallbackHttpServerTest { @@ -39,11 +42,20 @@ public class OAuth2AuthenticationCodeCallbackHttpServerTest { .build()) .get(); + private State state; + private AuthorizationCode authorizationCode; + + @Before + public void setUp() { + state = new State(); + authorizationCode = new AuthorizationCode(RandomStringUtils.randomAlphanumeric(20)); + } + @Test public void givenCallbackIsNotCalled_whenGetCode_thenTimesOut() { try (OAuth2AuthenticationCodeCallbackHttpServer server = - new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL, 1000)) { - Either r = server.getCode(); + new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL, state, 1000)) { + Either r = server.getAuthorizationCode(); assertThat("getting code didn't fail", r.isLeft()); assertEquals( "getting code did not time out when callback was not invoked", TIME_OUT, r.getLeft()); @@ -54,13 +66,12 @@ public void givenCallbackIsNotCalled_whenGetCode_thenTimesOut() { public void givenCallbackIsCalledWithCodeParameter_whenGetCode_thenReturnsCode() throws Exception { try (OAuth2AuthenticationCodeCallbackHttpServer server = - new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL)) { - String code = RandomStringUtils.randomAlphanumeric(20); - CompletableFuture> f = invokeCallback(Option.some(code)); - Either r = server.getCode(); + new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL, state)) { + CompletableFuture> f = invokeCallback(Option.some(authorizationCode)); + Either r = server.getAuthorizationCode(); assertThat("invoking callback failed", f.get().get().getStatusLine().getStatusCode() == 200); assertThat("getting code didn't succeed", r.isRight()); - assertEquals("incorrect code delivered", code, r.get()); + assertEquals("incorrect code delivered", authorizationCode.getValue(), r.get().getValue()); } } @@ -68,9 +79,9 @@ public void givenCallbackIsCalledWithCodeParameter_whenGetCode_thenReturnsCode() public void givenCallbackIsCalledWithoutCodeParameter_whenGetCode_thenFailsWithError() throws Exception { try (OAuth2AuthenticationCodeCallbackHttpServer server = - new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL)) { + new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL, state)) { CompletableFuture> f = invokeCallback(Option.none()); - Either r = server.getCode(); + Either r = server.getAuthorizationCode(); assertThat("invoking callback failed", f.get().get().getStatusLine().getStatusCode() == 200); assertThat("getting code succeeded although it should fail", r.isLeft()); assertEquals("incorrect code delivered", MISSING_AUTHENTICATION_CODE, r.left().get()); @@ -80,22 +91,23 @@ public void givenCallbackIsCalledWithoutCodeParameter_whenGetCode_thenFailsWithE @Test public void givenCallbackIsCalledTwice_whenGetCode_thenDoesNotBlock() throws Exception { try (OAuth2AuthenticationCodeCallbackHttpServer server = - new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL)) { - String code = RandomStringUtils.randomAlphanumeric(20); - invokeCallback(Option.some(code)); - server.getCode(); + new OAuth2AuthenticationCodeCallbackHttpServer(CALLBACK_URL, state)) { + invokeCallback(Option.some(authorizationCode)); + server.getAuthorizationCode(); HttpResponse response = invokeCallback(Option.none()).get(1, TimeUnit.SECONDS).get(); assertEquals("Expected internal server error", 500, response.getStatusLine().getStatusCode()); } } - private CompletableFuture> invokeCallback(Option code) { + private CompletableFuture> invokeCallback(Option code) { return CompletableFuture.supplyAsync( () -> Try.of( () -> { URIBuilder builder = new URIBuilder(CALLBACK_URL); - code.forEach(c -> builder.addParameter("code", c)); + code.forEach(c -> builder.addParameter("code", c.getValue())); + builder.addParameter("state", state.getValue()); + builder.addParameter("scope", "openid offline"); URI callbackUrlWithCode = builder.build(); HttpClient client = HttpClients.custom().disableAutomaticRetries().build(); HttpGet httpGet = new HttpGet(callbackUrlWithCode); diff --git a/src/test/java/io/carbynestack/cli/login/VcpTokenStoreTest.java b/src/test/java/io/carbynestack/cli/login/VcpTokenStoreTest.java index 7d1b6f8..ecc6d21 100644 --- a/src/test/java/io/carbynestack/cli/login/VcpTokenStoreTest.java +++ b/src/test/java/io/carbynestack/cli/login/VcpTokenStoreTest.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 @@ -7,14 +7,14 @@ package io.carbynestack.cli.login; import static io.carbynestack.cli.login.VcpTokenStore.*; -import static io.carbynestack.cli.login.VcpTokenStore.load; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.Mockito.*; -import com.github.scribejava.core.oauth.OAuth20Service; +import com.nimbusds.openid.connect.sdk.OIDCTokenResponse; +import com.nimbusds.openid.connect.sdk.token.OIDCTokens; import io.carbynestack.cli.TemporaryConfiguration; import io.carbynestack.cli.configuration.Configuration; import io.carbynestack.cli.configuration.ConfigurationUtil; @@ -27,30 +27,23 @@ import java.time.Instant; import java.util.Date; import org.apache.commons.lang3.RandomStringUtils; +import org.junit.Before; import org.junit.Rule; import org.junit.Test; -import org.junit.runner.RunWith; -import org.powermock.api.mockito.PowerMockito; -import org.powermock.core.classloader.annotations.PrepareForTest; -import org.powermock.modules.junit4.PowerMockRunner; +import org.mockito.Mockito; -@RunWith(PowerMockRunner.class) -@PrepareForTest(Configuration.class) public class VcpTokenStoreTest { - @Rule TemporaryConfiguration temporaryConfiguration = new TemporaryConfiguration(); + @Rule public TemporaryConfiguration temporaryConfiguration = new TemporaryConfiguration(); + private OIDCTokens oidcTokens; private static VcpTokenStore createStore(boolean expired) throws Exception { Date ref = !expired ? new Date() : Date.from(Instant.now().minusSeconds(2 * TokenUtils.VALIDITY)); Configuration config = ConfigurationUtil.getConfiguration(); return builder() - .token( - VcpToken.from( - ref, config.getProvider(1).getBaseUrl(), TokenUtils.createToken("apollo"))) - .token( - VcpToken.from( - ref, config.getProvider(2).getBaseUrl(), TokenUtils.createToken("starbuck"))) + .token(VcpToken.from(ref, config.getProvider(1).getBaseUrl(), TokenUtils.createToken())) + .token(VcpToken.from(ref, config.getProvider(2).getBaseUrl(), TokenUtils.createToken())) .build(); } @@ -60,6 +53,11 @@ private static Writer getFailingWriter() throws IOException { return w; } + @Before + public void configureMocks() throws Exception { + oidcTokens = TokenUtils.createToken(); + } + @Test public void givenDefaultDoesNotExist_whenLoad_thenFails() { setDefaultLocation(Option.some(Paths.get("home", RandomStringUtils.randomAlphabetic(10)))); @@ -93,31 +91,24 @@ public void givenWriterFails_whenPersist_thenFails() throws Exception { @Test public void givenValidTokens_whenRefresh_thenDoesNothing() throws Exception { - PowerMockito.mockStatic(Configuration.class); - when(Configuration.getInstance()).thenReturn(ConfigurationUtil.getConfiguration()); - OAuth20Service mockedService = mock(OAuth20Service.class); - VcpTokenStore store = - createStore(false).toBuilder().oAuth20ServiceProvider(c -> mockedService).build(); + VcpTokenStore store = createStore(false).toBuilder().build(); assertThat( "tokens in store are expired", store.getTokens().stream().noneMatch(VcpToken::isExpired)); store.refresh(); - verify(mockedService, times(0)).refreshAccessToken(any()); } @Test public void givenExpiredTokens_whenRefresh_thenRefreshesTokens() throws Exception { - PowerMockito.mockStatic(Configuration.class); - when(Configuration.getInstance()).thenReturn(ConfigurationUtil.getConfiguration()); - OAuth20Service mockedService = mock(OAuth20Service.class); - doReturn(TokenUtils.createToken("test")) - .when(mockedService) - .refreshAccessToken(any(), any(String.class)); - VcpTokenStore store = - createStore(true).toBuilder().oAuth20ServiceProvider(c -> mockedService).build(); + VcpTokenStore store = createStore(true).toBuilder().build(); + VcpTokenStore spyStore = spy(store); + doReturn(new OIDCTokenResponse(oidcTokens.toOIDCTokens())) + .when(spyStore) + .sendRefreshToken(Mockito.any(), Mockito.any(), anyBoolean(), anyList()); + assertThat( "tokens in store are not expired", - store.getTokens().stream().allMatch(VcpToken::isExpired)); - Either refreshed = store.refresh(); + spyStore.getTokens().stream().allMatch(VcpToken::isExpired)); + Either refreshed = spyStore.refresh(); assertThat("refresh failed", refreshed.isRight()); assertThat( "tokens in store are expired after refresh", @@ -126,12 +117,7 @@ public void givenExpiredTokens_whenRefresh_thenRefreshesTokens() throws Exceptio @Test public void givenExpiredTokensAndFailingProvider_whenRefresh_thenRefreshFails() throws Exception { - PowerMockito.mockStatic(Configuration.class); - when(Configuration.getInstance()).thenReturn(ConfigurationUtil.getConfiguration()); - OAuth20Service mockedService = mock(OAuth20Service.class); - doThrow(new IOException()).when(mockedService).refreshAccessToken(any(), any(String.class)); - VcpTokenStore store = - createStore(true).toBuilder().oAuth20ServiceProvider(c -> mockedService).build(); + VcpTokenStore store = createStore(true).toBuilder().build(); Either refreshed = store.refresh(); assertThat("refresh succeeded despite failing provider", refreshed.isLeft()); assertThat("wrong error returned", refreshed.getLeft() instanceof ByTokenError); diff --git a/src/test/java/io/carbynestack/cli/util/OAuthUtilTest.java b/src/test/java/io/carbynestack/cli/util/OAuthUtilTest.java new file mode 100644 index 0000000..ac53295 --- /dev/null +++ b/src/test/java/io/carbynestack/cli/util/OAuthUtilTest.java @@ -0,0 +1,114 @@ +/* + * Copyright (c) 2024 - for information on the respective copyright owner + * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. + * + * SPDX-License-Identifier: Apache-2.0 + */ + +package io.carbynestack.cli.util; + +import static com.github.tomakehurst.wiremock.client.WireMock.*; +import static com.github.tomakehurst.wiremock.core.WireMockConfiguration.options; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; + +import com.github.tomakehurst.wiremock.junit.WireMockRule; +import com.nimbusds.oauth2.sdk.http.HTTPRequest; +import com.nimbusds.oauth2.sdk.http.HTTPResponse; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.nio.file.Paths; +import java.security.KeyManagementException; +import java.security.KeyStoreException; +import java.security.NoSuchAlgorithmException; +import java.security.cert.CertificateException; +import java.util.Collections; +import java.util.Objects; +import javax.net.ssl.SSLHandshakeException; +import org.apache.http.HttpStatus; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; + +public class OAuthUtilTest { + private static final String KEY_STORE_PATH = + Objects.requireNonNull(OAuthUtilTest.class.getClassLoader().getResource("keyStoreA.jks")) + .getPath(); + private static final String KEY_STORE_A_PASSWORD = "verysecure"; + private static final String CERTIFICATE_PATH = + Objects.requireNonNull(OAuthUtilTest.class.getClassLoader().getResource("certA.pem")) + .getPath(); + private static final String GOOGLE_DIRECTIONS_REST_URI = + "https://maps.googleapis.com/maps/api/directions/json"; + private static final String TEST_ENDPOINT = "/test"; + private static final String SUCCESS_RESPONSE_STRING = "success"; + + private boolean initialized = false; + private URI testUri; + + @Rule + public WireMockRule wireMockRule = + new WireMockRule( + options() + .dynamicHttpsPort() + .keystorePath(KEY_STORE_PATH) + .keystorePassword(KEY_STORE_A_PASSWORD), + false); + + @Before + public void setUp() throws URISyntaxException { + if (!initialized) { + wireMockRule.stubFor( + get(urlEqualTo(TEST_ENDPOINT)) + .willReturn( + aResponse().withStatus(HttpStatus.SC_OK).withBody(SUCCESS_RESPONSE_STRING))); + testUri = new URI(String.format("%s%s", wireMockRule.baseUrl(), TEST_ENDPOINT)); + } + initialized = true; + } + + @Test + public void givenServerCertIsUntrusted_whenRequesting_thenThrows() { + HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.GET, testUri); + Exception actualException = assertThrows(Exception.class, httpRequest::send); + Assert.assertTrue(actualException.getCause() instanceof SSLHandshakeException); + } + + @Test + public void givenContextConfiguredTrustAll_whenRequesting_thenSucceed() + throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException { + HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.GET, testUri); + OAuthUtil.setSslContextForRequestWithConfiguration(httpRequest, true, null); + HTTPResponse response = httpRequest.send(); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(SUCCESS_RESPONSE_STRING, response.getBody().trim()); + } + + @Test + public void givenServerCertIsTrusted_whenRequesting_thenSucceed() + throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException { + HTTPRequest httpRequest = new HTTPRequest(HTTPRequest.Method.GET, testUri); + OAuthUtil.setSslContextForRequestWithConfiguration( + httpRequest, false, Collections.singletonList(Paths.get(CERTIFICATE_PATH))); + HTTPResponse response = httpRequest.send(); + assertEquals(HttpStatus.SC_OK, response.getStatusCode()); + assertEquals(SUCCESS_RESPONSE_STRING, response.getBody().trim()); + } + + @Test + public void givenCustomCertsDefined_whenRequestingServerWithCACert_thenSucceed() + throws IOException, CertificateException, NoSuchAlgorithmException, KeyStoreException, + KeyManagementException, URISyntaxException { + HTTPRequest httpRequest = + new HTTPRequest(HTTPRequest.Method.GET, new URI(GOOGLE_DIRECTIONS_REST_URI)); + OAuthUtil.setSslContextForRequestWithConfiguration( + httpRequest, false, Collections.singletonList(Paths.get(CERTIFICATE_PATH))); + HTTPResponse response = httpRequest.send(); + // Google Directions API returns 400 for this request but still validates the certificate + assertEquals(HttpStatus.SC_BAD_REQUEST, response.getStatusCode()); + } +} diff --git a/src/test/java/io/carbynestack/cli/util/TokenUtils.java b/src/test/java/io/carbynestack/cli/util/TokenUtils.java index fa3c277..188ed78 100644 --- a/src/test/java/io/carbynestack/cli/util/TokenUtils.java +++ b/src/test/java/io/carbynestack/cli/util/TokenUtils.java @@ -1,26 +1,43 @@ /* - * Copyright (c) 2021 - for information on the respective copyright owner + * Copyright (c) 2021-2024 - for information on the respective copyright owner * see the NOTICE file and/or the repository https://github.com/carbynestack/cli. * * SPDX-License-Identifier: Apache-2.0 */ package io.carbynestack.cli.util; -import com.github.scribejava.core.model.OAuth2AccessToken; +import static net.minidev.json.parser.JSONParser.DEFAULT_PERMISSIVE_MODE; + +import com.nimbusds.openid.connect.sdk.token.OIDCTokens; +import java.nio.file.Files; +import java.nio.file.Paths; import lombok.experimental.UtilityClass; +import net.minidev.json.JSONObject; +import net.minidev.json.parser.JSONParser; @UtilityClass public class TokenUtils { public final int VALIDITY = 24 * 60 * 60; - public OAuth2AccessToken createToken(String tag) { - return new OAuth2AccessToken( - String.format("%s-access-token", tag), - String.format("%s-token-type", tag), - VALIDITY, - String.format("%s-refresh-token", tag), - String.format("%s-scope", tag), - String.format("%s-raw-response", tag)); + public OIDCTokens createToken() { + try { + String jsonString = + new String(Files.readAllBytes(Paths.get("src/test/resources/id_token.json"))); + JSONObject jsonObject = + (JSONObject) new JSONParser(DEFAULT_PERMISSIVE_MODE).parse(jsonString); + return OIDCTokens.parse(jsonObject); + } catch (Exception e) { + throw new TokenCreationException(e); + } + } +} + +/* + * Avoiding throwing raw exception types. + */ +class TokenCreationException extends RuntimeException { + public TokenCreationException(Throwable cause) { + super(cause); } } diff --git a/src/test/resources/id_token.json b/src/test/resources/id_token.json new file mode 100644 index 0000000..c700df8 --- /dev/null +++ b/src/test/resources/id_token.json @@ -0,0 +1,8 @@ +{ + "access_token": "ory_at_vyII11j_BAAbaIEaifIeQkksQWEznsQqFKv5wR8DtiU.NeWBSTRlPtWwOTFW_BBS4-cDws3KaG6bWNd-ne1LTIE", + "expires_in": 7200, + "id_token": "eyJhbGciOiJSUzI1NiIsImtpZCI6ImNlYWMwZTU5LThiNmUtNGNhNy1iNGI4LWYyYzNjNjZmNTNjMyIsInR5cCI6IkpXVCJ9.eyJhbXIiOlsicGFzc3dvcmQiXSwiYXRfaGFzaCI6Im5US1JTTEhrVllTZnZJTlgyUjQ2VmciLCJhdWQiOlsiM2E2NTE0ODUtZmY4NC00YjIwLWI4ZDYtNTU3NGVkZDM1OTJmIl0sImF1dGhfdGltZSI6MTcxNjQ1NDIzNSwiZXhwIjoxNzE2NDcxNDkwLCJpYXQiOjE3MTY0Njc4OTAsImlzcyI6Imh0dHA6Ly8xMjcuMC4wLjE6NDQ0NCIsImp0aSI6Ijk4MzI1MTUxLTQ1NjMtNGQ0MC04YTIwLWZmMDkzNTYxNTVlNCIsInJhdCI6MTcxNjQ2Nzg2Nywic2lkIjoiMTZkMDhiMTMtNDZmZi00ODI1LWJhMmEtOTJiM2RlMjQyNjdhIiwic3ViIjoiNzZiMTZjMWEtODY5MS00YjUxLTk5NjktZTk0MmQwYTcxZWFkIn0.kKEdwPxoNiG_GEmkbJ_WXVsVqE_BO3ahDXNl9vE77nbULDNqHNJT5oK6s9W-BKgf0d3Inm49diTMz3yYNolhOWowSKMKC90CnHPwF6IyHS4CmdTexcKhwswP-vyHob4olRVQEKNuhCRKXDwfSdBqZvIo_4VD5xYAlkwlkjzdCc7-T7t0R9PbBb2bHwEFGn2X7Hrr3sBC60m3aW5nh2VA9UUnmIuCyrPRpH1D_gg6Wx2IQqa_cTv7FLaBKpTaOFBEsECOVN4ftwU41h488v6LOnmMEG1Fmw-hzX3ynkDnoZ2yCE2TAOBG_2r6zIrzrbH09eVd5bNqZ88jInBbghrnreE49ii_qKRypdp337fbhHeuBYoHPCqWDkW8rablz1sM31NPUHS7oVpONFmWxybm1bnuuCknzk_pzU3xUd-VK0160e7xeci0XV4hlbH1NPMdqPbTutJ3bT4r5ZBsrtVBFWr6QTjBozdwcZQm5_1zuW2-GDSsosLqexphh-DYPD58xMmNaztpoCtUiqyaGjxpmdT-scLAvXy_wjQW4F-IIBHOnSm9RsJKCal51xf-EoqL9-i7mAN2dtYij1AUzolVHBa-0GFNAlbLJ8Hi_0RwZQ43w8Sk0NmU1eGJlMie3Qm3uo8znM4If2xc_v9PT8OD5KS4wn4oe9CX3Txf1ptvpA0", + "refresh_token": "ory_rt_myz1l2yNzPf_zs5rUejMvcM4YxejMyD9GPjJI7-C81g.WnpxfjiI9UyQsUnU6klUGmjw2LoMoEDKN9ZfgtZz0n0", + "scope": "offline openid", + "token_type": "bearer" +}