Browse Source

Merge pull request #80 from LDAPAccountManager/webauthn

Webauthn
pull/85/head
gruberroland 3 years ago
committed by GitHub
parent
commit
7b222d9edb
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .travis.yml
  2. 2
      composer.json
  3. 67
      lam-packaging/debian/copyright
  4. 1
      lam-packaging/docker/Dockerfile
  5. 5
      lam/HISTORY
  6. 10
      lam/composer.json
  7. 1259
      lam/composer.lock
  8. 1
      lam/config/.gitignore
  9. 67
      lam/copyright
  10. 47
      lam/docs/manual-sources/appendix-security.xml
  11. 59
      lam/docs/manual-sources/chapter-configuration.xml
  12. 2
      lam/docs/manual-sources/chapter-installation.xml
  13. 47
      lam/docs/manual-sources/chapter-selfService.xml
  14. 17
      lam/docs/manual-sources/chapter-tools.xml
  15. BIN
      lam/docs/manual-sources/images/configGeneral8.png
  16. BIN
      lam/docs/manual-sources/images/tool_webauthn1.png
  17. BIN
      lam/docs/manual-sources/images/webauthn.png
  18. 2
      lam/docs/manual-sources/overview.xml
  19. BIN
      lam/graphics/webauthn.png
  20. 31
      lam/graphics/webauthn.svg
  21. 4
      lam/help/help.inc
  22. 159
      lam/lib/2factor.inc
  23. 7
      lam/lib/3rdParty/composer/autoload.php
  24. 11
      lam/lib/3rdParty/composer/beberlei/assert/LICENSE
  25. 63
      lam/lib/3rdParty/composer/beberlei/assert/composer.json
  26. 96
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assert.php
  27. 2825
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assertion.php
  28. 254
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionChain.php
  29. 35
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php
  30. 76
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/InvalidArgumentException.php
  31. 230
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertion.php
  32. 55
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertionException.php
  33. 80
      lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/functions.php
  34. 10
      lam/lib/3rdParty/composer/beberlei/assert/phpstan-code.neon
  35. 10
      lam/lib/3rdParty/composer/beberlei/assert/phpstan-tests.neon
  36. 445
      lam/lib/3rdParty/composer/composer/ClassLoader.php
  37. 56
      lam/lib/3rdParty/composer/composer/LICENSE
  38. 9
      lam/lib/3rdParty/composer/composer/autoload_classmap.php
  39. 14
      lam/lib/3rdParty/composer/composer/autoload_files.php
  40. 9
      lam/lib/3rdParty/composer/composer/autoload_namespaces.php
  41. 28
      lam/lib/3rdParty/composer/composer/autoload_psr4.php
  42. 70
      lam/lib/3rdParty/composer/composer/autoload_real.php
  43. 157
      lam/lib/3rdParty/composer/composer/autoload_static.php
  44. 1285
      lam/lib/3rdParty/composer/composer/installed.json
  45. 38
      lam/lib/3rdParty/composer/fgrosse/phpasn1/CHANGELOG.md
  46. 19
      lam/lib/3rdParty/composer/fgrosse/phpasn1/LICENSE
  47. 167
      lam/lib/3rdParty/composer/fgrosse/phpasn1/README.md
  48. 47
      lam/lib/3rdParty/composer/fgrosse/phpasn1/composer.json
  49. 355
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ASNObject.php
  50. 136
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractString.php
  51. 78
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/AbstractTime.php
  52. 63
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Base128.php
  53. 35
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/AttributeTypeAndValue.php
  54. 37
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RDNString.php
  55. 50
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Composite/RelativeDistinguishedName.php
  56. 191
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Construct.php
  57. 15
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/NotImplementedException.php
  58. 29
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Exception/ParserException.php
  59. 131
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/ExplicitlyTaggedObject.php
  60. 339
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Identifier.php
  61. 198
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/OID.php
  62. 32
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Parsable.php
  63. 70
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/TemplateParser.php
  64. 41
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BMPString.php
  65. 88
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/BitString.php
  66. 75
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Boolean.php
  67. 28
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/CharacterString.php
  68. 21
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Enumerated.php
  69. 34
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralString.php
  70. 134
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GeneralizedTime.php
  71. 34
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/GraphicString.php
  72. 35
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/IA5String.php
  73. 130
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Integer.php
  74. 54
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NullObject.php
  75. 38
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/NumericString.php
  76. 26
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectDescriptor.php
  77. 138
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/ObjectIdentifier.php
  78. 91
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/OctetString.php
  79. 53
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/PrintableString.php
  80. 57
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/RelativeObjectIdentifier.php
  81. 23
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Sequence.php
  82. 21
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/Set.php
  83. 36
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/T61String.php
  84. 77
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTCTime.php
  85. 34
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UTF8String.php
  86. 36
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/UniversalString.php
  87. 34
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/Universal/VisibleString.php
  88. 59
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownConstructedObject.php
  89. 59
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/ASN1/UnknownObject.php
  90. 197
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigInteger.php
  91. 133
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerBcmath.php
  92. 133
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/Utility/BigIntegerGmp.php
  93. 22
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/AlgorithmIdentifier.php
  94. 68
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/Attributes.php
  95. 137
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CSR/CSR.php
  96. 100
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateExtensions.php
  97. 108
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/CertificateSubject.php
  98. 35
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PrivateKey.php
  99. 35
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/PublicKey.php
  100. 28
      lam/lib/3rdParty/composer/fgrosse/phpasn1/lib/X509/SAN/DNSName.php

2
.travis.yml

@ -3,7 +3,7 @@ addons:
sonarcloud:
organization: "ldap-account-manager"
php:
- '5.6'
- '7.3'
cache:
directories:

2
composer.json

@ -3,4 +3,4 @@
"phpunit/phpunit" : "5.7.27",
"squizlabs/php_codesniffer" : "3.4.0"
}
}
}

67
lam-packaging/debian/copyright

@ -179,6 +179,7 @@ A:
information, contact: tavmjong @ free . fr.
B:
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -200,6 +201,7 @@ B:
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
C:
New BSD License
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@ -391,6 +393,7 @@ D:
Library.
E:
Duo
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@ -415,10 +418,73 @@ E:
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
F:
3-Clause BSD License
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 holder 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 HOLDER 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.
G:
2-Clause BSD License
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.
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 HOLDER 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.
Programs and licenses with other licenses and/or authors than the
main license and authors:
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano
lib/3rdParty/composer/fgrosse B 2015 Friedrich Große
lib/3rdParty/composer/nyholm B 2016 Tobias Nyholm
lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises
lib/3rdParty/composer/php-http B 2015 PHP HTTP Team
lib/3rdParty/composer/psr B 2018 PHP Framework Interoperability Group
lib/3rdParty/composer/ramsey B 2018 Ben Ramsey
lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs
lib/3rdParty/composer/symfony B 2019 Fabien Potencier
lib/3rdParty/composer/web-auth B 2018 Spomky-Labs
lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
@ -438,6 +504,7 @@ templates/lib/extra/cropperjs B 2018 Chen Fengyuan
style/600_cropper*.css B 2018 Chen Fengyuan
templates/lib/extra/duo/*.js E 2019 Duo Security
lib/3rdParty/duo/*.php E 2019 Duo Security
graphics/webauthn.svg F 2017 Duo Security, Inc.
templates/lib/600_jquery.magnific-popup.js B 2016 Dmitry Semenov
style/610_magnific-popup.css B 2016 Dmitry Semenov
style/responsive/105_normalize.css B Nicolas Gallagher and Jonathan Neal

1
lam-packaging/docker/Dockerfile

@ -51,6 +51,7 @@ RUN apt-get update && \
php-phpseclib \
php-xml \
php-zip \
php-imap \
wget \
&& \
rm /etc/apache2/sites-enabled/*default* && \

5
lam/HISTORY

@ -1,3 +1,8 @@
March 2020 7.1
- PHP 7 required
- Webauthn/FIDO2 support for 2-factor-authentication (requires PHP 7.2)
21.12.2019 7.0
- Lamdaemon can be configured with directory prefix for homedirs
- Account list filters match on substrings instead of whole value

10
lam/composer.json

@ -0,0 +1,10 @@
{
"config": {
"vendor-dir": "lib/3rdParty/composer"
},
"require" : {
"web-auth/webauthn-lib" : "2.1.7",
"symfony/http-foundation" : "5.0.0",
"symfony/psr-http-message-bridge" : "1.3.0"
}
}

1259
lam/composer.lock
File diff suppressed because it is too large
View File

1
lam/config/.gitignore

@ -3,3 +3,4 @@ config.cfg
/serverCerts.pem
/pdf/
/profiles/
*.sqlite

67
lam/copyright

@ -178,6 +178,7 @@ A:
information, contact: tavmjong @ free . fr.
B:
MIT License
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
@ -199,6 +200,7 @@ B:
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
C:
New BSD License
Redistribution and use in source and binary forms, with or without modification,
are permitted provided that the following conditions are met:
@ -390,6 +392,7 @@ D:
Library.
E:
Duo
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
@ -414,10 +417,73 @@ E:
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
F:
3-Clause BSD License
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 holder 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 HOLDER 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.
G:
2-Clause BSD License
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.
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 HOLDER 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.
Programs and licenses with other licenses and/or authors than the
main license and authors:
lib/3rdParty/composer/beberlei G 2013 Benjamin Eberlei
lib/3rdParty/composer/composer B Nils Adermann, Jordi Boggiano
lib/3rdParty/composer/fgrosse B 2015 Friedrich Große
lib/3rdParty/composer/nyholm B 2016 Tobias Nyholm
lib/3rdParty/composer/paragonie B 2015 Paragon Initiative Enterprises
lib/3rdParty/composer/php-http B 2015 PHP HTTP Team
lib/3rdParty/composer/psr B 2018 PHP Framework Interoperability Group
lib/3rdParty/composer/ramsey B 2018 Ben Ramsey
lib/3rdParty/composer/spomky-labs B 2018 Spomky-Labs
lib/3rdParty/composer/symfony B 2019 Fabien Potencier
lib/3rdParty/composer/web-auth B 2018 Spomky-Labs
lib/3rdParty/tcpdf D 2018 Nicola Asuni - Tecnick.com LTD
lib/3rdParty/tcpdf/fonts/DejaVu*.ttf A Public Domain, Bitstream, Inc., Tavmjong Bah
lib/3rdParty/tcpdf/fonts/DejaVu*.z A Public Domain, Bitstream, Inc., Tavmjong Bah
@ -437,6 +503,7 @@ templates/lib/extra/cropperjs B 2018 Chen Fengyuan
style/600_cropper*.css B 2018 Chen Fengyuan
templates/lib/extra/duo/*.js E 2019 Duo Security
lib/3rdParty/duo/*.php E 2019 Duo Security
graphics/webauthn.svg F 2017 Duo Security, Inc.
templates/lib/600_jquery.magnific-popup.js B 2016 Dmitry Semenov
style/610_magnific-popup.css B 2016 Dmitry Semenov
style/responsive/105_normalize.css B Nicolas Gallagher and Jonathan Neal

47
lam/docs/manual-sources/appendix-security.xml

@ -445,4 +445,51 @@ semodule -i httpdlocal.pp</programlisting>
</programlisting>
</section>
</section>
<section id="a_webauthn">
<title>Webauthn/FIDO2</title>
<para>LAM allows to secure logins via <ulink
url="https://en.wikipedia.org/wiki/WebAuthn">Webauthn/FIDO2</ulink>. This
means your users login with their LDAP password and an additional hardware
token (e.g. Yubico Security Key, Windows Hello and many more).</para>
<para>Webauthn/FIDO2 is a very strong 2-factor-authentication method as it
also checks the website domain. This prevents attacks via web
proxies.</para>
<para>To use this feature you need to activate the 2-factor authentication
in LAM.</para>
<para><emphasis role="bold">LAM admin interface</emphasis></para>
<para>Please activate Webauthn/FIDO2 in your <link
linkend="conf_serverprofile_2fa">LAM server profile</link>. Then users
will be asked to authenticate via Webauthn/FIDO2 on each login.</para>
<para>If no device is registered for a user then LAM will ask for this
during login. Afterwards, users can manage their devices with the <link
linkend="tool_webauthn">Webauthn tool</link>.</para>
<para><emphasis role="bold">LAM Self Service</emphasis></para>
<para>Please activate Webauthn/FIDO2 in your <link
linkend="selfservice_2fa">LAM self service profile</link>. Then users will
be asked to authenticate via Webauthn/FIDO2 on each login.</para>
<para>If no device is registered for a user then LAM will ask for this
during login. Afterwards, users can manage their devices with the <link
linkend="selfservice_fields">Webauthn field</link>.</para>
<para><emphasis role="bold">Global device management</emphasis></para>
<para>This is for cases where one of your users has no more access to his
device and cannot login anymore. In this case you can delete his device(s)
in the <link linkend="confmain_webauthn">LAM main
configuration</link>.</para>
<para>Note that devices can only be deleted. Registration of devices can
only be done by the user during login or on the management pages listed
above.</para>
</section>
</appendix>

59
lam/docs/manual-sources/chapter-configuration.xml

@ -259,6 +259,33 @@
</screenshot>
</section>
<section id="confmain_webauthn">
<title>Webauthn/FIDO2 devices</title>
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2 appendix</link>
for an overview about Webauthn/FIDO2 in LAM.</para>
<para>Here you can delete any webauthn device registrations. This
section is only shown if at least one device is registered.</para>
<para>Enter a part of the user's DN in the input box and perform a
search. LAM will show users and devices that match the search. You can
then delete a device registration. If the user has no more registered
devices then LAM will ask for registration on next login.</para>
<para>Note: You cannot add any device here. This can only be done by the
user during login, <link linkend="tool_webauthn">webauthn tool</link> or
self service.</para>
<para><screenshot>
<mediaobject>
<imageobject>
<imagedata fileref="images/configGeneral8.png"/>
</imageobject>
</mediaobject>
</screenshot></para>
</section>
<section>
<title>Change master password</title>
@ -631,7 +658,8 @@
</mediaobject>
</screenshot>
<para><emphasis role="bold">2-factor authentication</emphasis></para>
<para id="conf_serverprofile_2fa"><emphasis role="bold">2-factor
authentication</emphasis></para>
<para>LAM supports 2-factor authentication for your users. This means
the user will not only authenticate by user+password but also with
@ -655,6 +683,11 @@
<listitem>
<para><ulink url="https://duo.com/">Duo</ulink></para>
</listitem>
<listitem>
<para><ulink
url="https://webauthn.io/">Webauthn/FIDO2</ulink></para>
</listitem>
</itemizedlist>
<para>Configuration options:</para>
@ -752,6 +785,30 @@
</listitem>
</itemizedlist>
<para><emphasis role="bold">Webauthn/FIDO2</emphasis></para>
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2
appendix</link> for an overview about Webauthn/FIDO2 in LAM.</para>
<para>Users will be asked to register a device during login if no
device is setup.</para>
<itemizedlist>
<listitem>
<para>Domain: Please enter the WebAuthn domain. This is the public
domain of the web server (e.g. "example.com"). Do not include
protocol or port. Browsers will reject authentication if the
domain does not match the web server domain.</para>
</listitem>
<listitem>
<para>Optional: By default LAM will enforce to use a 2FA device
and reject users that do not setup one. You can set this check to
optional. But if a user has setup a device then this will always
be required.</para>
</listitem>
</itemizedlist>
<screenshot>
<mediaobject>
<imageobject>

2
lam/docs/manual-sources/chapter-installation.xml

@ -15,7 +15,7 @@
<itemizedlist>
<listitem>
<para>Apache/Nginx webserver (SSL recommended) with PHP module (PHP
(&gt;= 5.6.0) with ldap, gettext, xml, openssl and optional
(&gt;= 7.0.0) with ldap, gettext, xml, openssl and optional
OpenSSL)</para>
</listitem>

47
lam/docs/manual-sources/chapter-selfService.xml

@ -304,7 +304,7 @@
<para/>
<section>
<section id="selfservice_2fa">
<title>2-factor authentication</title>
<para>LAM supports 2-factor authentication for your users. This means
@ -329,6 +329,11 @@
<listitem>
<para><ulink url="https://duo.com/">Duo</ulink></para>
</listitem>
<listitem>
<para><ulink
url="https://en.wikipedia.org/wiki/WebAuthn">Webauthn/FIDO2</ulink></para>
</listitem>
</itemizedlist>
<para><emphasis role="bold">privacyIDEA</emphasis></para>
@ -424,6 +429,30 @@
</listitem>
</itemizedlist>
<para><emphasis role="bold">Webauthn/FIDO2</emphasis></para>
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2
appendix</link> for an overview about Webauthn/FIDO2 in LAM.</para>
<para>Users will be asked to register a device during login if no
device is setup.</para>
<itemizedlist>
<listitem>
<para>Domain: Please enter the WebAuthn domain. This is the public
domain of the web server (e.g. "example.com"). Do not include
protocol or port. Browsers will reject authentication if the
domain does not match the web server domain.</para>
</listitem>
<listitem>
<para>Optional: By default LAM will enforce to use a 2FA device
and reject users that do not setup one. You can set this check to
optional. But if a user has setup a device then this will always
be required.</para>
</listitem>
</itemizedlist>
<screenshot>
<mediaobject>
<imageobject>
@ -495,7 +524,8 @@
</mediaobject>
</screenshot>
<para><emphasis role="bold">Possible input fields</emphasis></para>
<para id="selfservice_fields"><emphasis role="bold">Possible input
fields</emphasis></para>
<para>This is a list of input fields you may add to the self service
page.</para>
@ -985,6 +1015,19 @@
each time the Windows password is changed.</entry>
</row>
<row>
<entry><inlinemediaobject>
<imageobject>
<imagedata fileref="images/webauthn.png"/>
</imageobject>
</inlinemediaobject>Webauthn</entry>
<entry>Webauthn devices</entry>
<entry>Allows the user to manage his webauthn/FIDO2 security
keys.</entry>
</row>
<row>
<entry morerows="1"><inlinemediaobject>
<imageobject>

17
lam/docs/manual-sources/chapter-tools.xml

@ -420,6 +420,23 @@
</screenshot>
</section>
<section>
<title id="tool_webauthn">Webauthn devices</title>
<para>See the <link linkend="a_webauthn">Webauthn/FIDO2 appendix</link>
for an overview about Webauthn/FIDO2 in LAM.</para>
<para>Here you can manage your webauthn/FIDO2 devices.</para>
<para>You can register additional security devices and remove old ones. If
no more device is registered then LAM will ask you for registration on
next login.</para>
<screenshot>
<graphic fileref="images/tool_webauthn1.png"/>
</screenshot>
</section>
<section>
<title>Tests</title>

BIN
lam/docs/manual-sources/images/configGeneral8.png

After

Width: 1365  |  Height: 361  |  Size: 35 KiB

BIN
lam/docs/manual-sources/images/tool_webauthn1.png

After

Width: 1579  |  Height: 492  |  Size: 62 KiB

BIN
lam/docs/manual-sources/images/webauthn.png

After

Width: 16  |  Height: 16  |  Size: 810 B

2
lam/docs/manual-sources/overview.xml

@ -63,7 +63,7 @@
<itemizedlist>
<listitem>
<para>PHP (&gt;= 5.6.0)</para>
<para>PHP (&gt;= 7.0.0)</para>
</listitem>
<listitem>

BIN
lam/graphics/webauthn.png

After

Width: 16  |  Height: 16  |  Size: 810 B

31
lam/graphics/webauthn.svg
File diff suppressed because it is too large
View File

4
lam/help/help.inc

@ -179,6 +179,8 @@ $helpArray = array (
"Text" => _("Here you can input simple filter expressions (e.g. 'value' or 'v*'). The filter is case-insensitive.")),
"251" => array ("Headline" => _("Remote server"),
"Text" => _("Please enter the syslog remote server in format \"server:port\".")),
"252" => array ("Headline" => _("User DN"),
"Text" => _("Please enter a part of the user's DN to search for registered devices.")),
"260" => array ("Headline" => _("Additional LDAP filter"),
"Text" => _('Use this to enter an additional LDAP filter (e.g. "(cn!=admin)") to reduce the number of visible elements for this account type.')
. ' ' . _('You can use the wildcard @@LOGIN_DN@@ which will be substituted with the DN of the user who is currently logged in to LAM.')
@ -329,6 +331,8 @@ $helpArray = array (
"Text" => _('This text is displayed as footer on the self service main page.')),
"528" => array ("Headline" => _('User name attribute'),
"Text" => _('The attribute (e.g. "uid") that contains the user name for the 2-factor service.')),
"529" => array ("Headline" => _('Domain'),
"Text" => _('Please enter the WebAuthn domain. This is the public domain of the webserver (e.g. "example.com"). Do not include protocol or port.')),
"550" => array ("Headline" => _("From address"),
"Text" => _("This email address will be set as sender address of all password mails. If empty the system default (php.ini) will be used.")),
"551" => array ("Headline" => _("Subject"),

159
lam/lib/2factor.inc

@ -1,14 +1,23 @@
<?php
namespace LAM\LIB\TWO_FACTOR;
use \htmlResponsiveRow;
use \LAM\LOGIN\WEBAUTHN\WebauthnManager;
use \selfServiceProfile;
use \LAMConfig;
use \htmlScript;
use \htmlIframe;
use \htmlImage;
use \htmlButton;
use \htmlJavaScript;
use \htmlStatusMessage;
use \htmlOutputText;
use \htmlDiv;
use \LAMException;
use \Webauthn\PublicKeyCredentialCreationOptions;
/*
This code is part of LDAP Account Manager (http://www.ldap-account-manager.org/)
Copyright (C) 2017 - 2019 Roland Gruber
Copyright (C) 2017 - 2020 Roland Gruber
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@ -455,7 +464,7 @@ class DuoProvider extends BaseProvider {
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::verify2ndFactor()
*/
public function verify2ndFactor($user, $password, $serial, $twoFactorInput) {
logNewMessage(LOG_DEBUG, 'PrivacyIDEAProvider: Checking 2nd factor for ' . $user);
logNewMessage(LOG_DEBUG, 'DuoProvider: Checking 2nd factor for ' . $user);
$loginAttribute = $this->getLoginAttributeValue($user);
$response = $_POST['sig_response'];
include_once(__DIR__ . "/3rdParty/duo/Web.php");
@ -473,6 +482,140 @@ class DuoProvider extends BaseProvider {
}
/**
* Provider for Webauthn.
*/
class WebauthnProvider extends BaseProvider {
/**
* Constructor.
*
* @param TwoFactorConfiguration $config configuration
*/
public function __construct($config) {
$this->config = $config;
}
/**
* {@inheritDoc}
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::getSerials()
*/
public function getSerials($user, $password) {
return array('WEBAUTHN');
}
/**
* {@inheritDoc}
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::isShowSubmitButton()
*/
public function isShowSubmitButton() {
return false;
}
/**
* {@inheritDoc}
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::hasCustomInputForm()
*/
public function hasCustomInputForm() {
return true;
}
/**
* {@inheritDoc}
* @see \LAM\LIB\TWO_FACTOR\BaseProvider::addCustomInput()
*/
public function addCustomInput(&$row, $userDn) {
if (version_compare(phpversion(), '7.2.0') < 0) {
$row->add(new htmlStatusMessage('ERROR', 'Webauthn requires PHP 7.2.'), 12);
return;
}
if (!extension_loaded('PDO')) {
$row->add(new htmlStatusMessage('ERROR', 'Webauthn requires the PDO extension for PHP.'), 12);
return;
}
$pdoDrivers = \PDO::getAvailableDrivers();
if (!in_array('sqlite', $pdoDrivers)) {
$row->add(new htmlStatusMessage('ERROR', 'Webauthn requires the sqlite PDO driver for PHP.'), 12);
return;
}
include_once __DIR__ . '/webauthn.inc';
$webauthnManager = $this->getWebauthnManager();
$hasTokens = $webauthnManager->isRegistered($userDn);
if ($hasTokens) {
$row->add(new htmlStatusMessage('INFO', _('Please authenticate with your security device.')), 12);
}
else {
$row->add(new htmlStatusMessage('INFO', _('Please register a security device.')), 12);
}
$row->addVerticalSpacer('2rem');
$pathPrefix = $this->config->isSelfService ? '../' : '';
$selfServiceParam = $this->config->isSelfService ? 'true' : 'false';
$row->add(new htmlImage($pathPrefix . '../graphics/webauthn.svg'), 12);
$row->addVerticalSpacer('1rem');
$registerButton = new htmlButton('register_webauthn', _('Register new key'));
$registerButton->setCSSClasses(array('fullwidth hidden'));
$row->add($registerButton, 12);
$loginButton = new htmlButton('login_webauthn', _('Login'));
$loginButton->setCSSClasses(array('fullwidth hidden'));
$row->add($loginButton, 12);
$errorMessage = new htmlStatusMessage('ERROR', '', _('This service requires a browser with "WebAuthn" support.'));
$row->add(new htmlDiv(null, $errorMessage, array('hidden webauthn-error')), 12);
if ($this->config->twoFactorAuthenticationOptional === true) {
if (!$hasTokens) {
$skipButton = new htmlButton('skip_webauthn', _('Skip'));
$skipButton->setCSSClasses(array('fullwidth'));
$row->add($skipButton, 12);
}
}
$errorMessageDiv = new htmlDiv('generic-webauthn-error', new htmlOutputText(''));
$errorMessageDiv->addDataAttribute('button', _('Ok'));
$errorMessageDiv->addDataAttribute('title', _('Webauthn failed'));
$row->add($errorMessageDiv, 12);
$row->add(new htmlJavaScript('window.lam.webauthn.start(\'' . $pathPrefix . '\', ' . $selfServiceParam . ');'), 0);
}
/**
* Returns the webauthn manager.
*
* @return WebauthnManager manager
*/
public function getWebauthnManager() {
return new WebauthnManager();
}
/**
* {@inheritDoc}
* @see \LAM\LIB\TWO_FACTOR\TwoFactorProvider::verify2ndFactor()
*/
public function verify2ndFactor($user, $password, $serial, $twoFactorInput) {
logNewMessage(LOG_DEBUG, 'WebauthnProvider: Checking 2nd factor for ' . $user);
include_once __DIR__ . '/webauthn.inc';
$webauthnManager = $this->getWebauthnManager();
if (!empty($_SESSION['ldap'])) {
$userDn = $_SESSION['ldap']->getUserName();
}
else {
$userDn = lamDecrypt($_SESSION['selfService_clientDN'], 'SelfService');
}
$hasTokens = $webauthnManager->isRegistered($userDn);
if (!$hasTokens) {
if ($this->config->twoFactorAuthenticationOptional && !$webauthnManager->isRegistered($user) && ($_POST['sig_response'] === 'skip')) {
logNewMessage(LOG_DEBUG, 'Skipped 2FA for ' . $user . ' as no devices are registered and 2FA is optional.');
return true;
}
$response = base64_decode($_POST['sig_response']);
$registrationObject = PublicKeyCredentialCreationOptions::createFromString($_SESSION['webauthn_registration']);
return $webauthnManager->storeNewRegistration($registrationObject, $response);
}
else {
logNewMessage(LOG_DEBUG, 'Checking webauthn response of ' . $userDn);
$response = base64_decode($_POST['sig_response']);
return $webauthnManager->isValidAuthentication($response, $userDn);
}
}
}
/**
* Returns the correct 2 factor provider.
*/
@ -486,6 +629,8 @@ class TwoFactorProviderService {
const TWO_FACTOR_YUBICO = 'yubico';
/** 2factor authentication via DUO */
const TWO_FACTOR_DUO = 'duo';
/** 2factor authentication via webauthn */
const TWO_FACTOR_WEBAUTHN = 'webauthn';
private $config;
@ -520,6 +665,9 @@ class TwoFactorProviderService {
elseif ($this->config->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_DUO) {
return new DuoProvider($this->config);
}
elseif ($this->config->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_WEBAUTHN) {
return new WebauthnProvider($this->config);
}
throw new \Exception('Invalid provider: ' . $this->config->twoFactorAuthentication);
}
@ -534,6 +682,7 @@ class TwoFactorProviderService {
$tfConfig->isSelfService = true;
$tfConfig->twoFactorAuthentication = $profile->twoFactorAuthentication;
$tfConfig->twoFactorAuthenticationInsecure = $profile->twoFactorAuthenticationInsecure;
$tfConfig->twoFactorAuthenticationOptional = $profile->twoFactorAuthenticationOptional;
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $profile->twoFactorAuthenticationURL);
}
@ -573,6 +722,7 @@ class TwoFactorProviderService {
$tfConfig->isSelfService = false;
$tfConfig->twoFactorAuthentication = $conf->getTwoFactorAuthentication();
$tfConfig->twoFactorAuthenticationInsecure = $conf->getTwoFactorAuthenticationInsecure();
$tfConfig->twoFactorAuthenticationOptional = $conf->getTwoFactorAuthenticationOptional();
if ($tfConfig->twoFactorAuthentication == TwoFactorProviderService::TWO_FACTOR_YUBICO) {
$tfConfig->twoFactorAuthenticationURL = explode("\r\n", $conf->getTwoFactorAuthenticationURL());
}
@ -641,4 +791,9 @@ class TwoFactorConfiguration {
*/
public $twoFactorAuthenticationSerialAttributeName = null;
/**
* @var bool 2FA is optional
*/
public $twoFactorAuthenticationOptional = false;
}

7
lam/lib/3rdParty/composer/autoload.php

@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInited73ceb9c1bdec18b7c6d09764d1bce5::getLoader();

11
lam/lib/3rdParty/composer/beberlei/assert/LICENSE

@ -0,0 +1,11 @@
Copyright (c) 2011-2013, Benjamin Eberlei
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
- Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
- Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.

63
lam/lib/3rdParty/composer/beberlei/assert/composer.json

@ -0,0 +1,63 @@
{
"name": "beberlei/assert",
"description": "Thin assertion library for input validation in business models.",
"authors": [
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de",
"role": "Lead Developer"
},
{
"name": "Richard Quadling",
"email": "rquadling@gmail.com",
"role": "Collaborator"
}
],
"license": "BSD-2-Clause",
"keywords": [
"assert",
"assertion",
"validation"
],
"autoload": {
"psr-4": {
"Assert\\": "lib/Assert"
},
"files": [
"lib/Assert/functions.php"
]
},
"autoload-dev": {
"psr-4": {
"Assert\\Tests\\": "tests/Assert/Tests"
},
"files": [
"tests/Assert/Tests/Fixtures/functions.php"
]
},
"config": {
"sort-packages": true
},
"require": {
"php": "^7",
"ext-simplexml": "*",
"ext-mbstring": "*",
"ext-ctype": "*",
"ext-json": "*"
},
"require-dev": {
"friendsofphp/php-cs-fixer": "*",
"phpstan/phpstan-shim": "*",
"phpunit/phpunit": ">=6.0.0 <8"
},
"scripts": {
"assert:generate-docs": "php bin/generate_method_docs.php",
"assert:cs-lint": "php-cs-fixer fix --diff -vvv --dry-run",
"assert:cs-fix": "php-cs-fixer fix . -vvv || true",
"assert:sa-code": "vendor/bin/phpstan analyse --configuration=phpstan-code.neon --no-progress --ansi -l 7 bin lib",
"assert:sa-tests": "vendor/bin/phpstan analyse --configuration=phpstan-tests.neon --no-progress --ansi -l 7 tests"
},
"suggest": {
"ext-intl": "Needed to allow Assertion::count(), Assertion::isCountable(), Assertion::minCount(), and Assertion::maxCount() to operate on ResourceBundles"
}
}

96
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assert.php

@ -0,0 +1,96 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
/**
* AssertionChain factory.
*/
abstract class Assert
{
/** @var string */
protected static $lazyAssertionExceptionClass = LazyAssertionException::class;
/** @var string */
protected static $assertionClass = Assertion::class;
/**
* Start validation on a value, returns {@link AssertionChain}.
*
* The invocation of this method starts an assertion chain
* that is happening on the passed value.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
* @param string|null $defaultPropertyPath
*
* @return AssertionChain
*
* @example
*
* Assert::that($value)->notEmpty()->integer();
* Assert::that($value)->nullOr()->string()->startsWith("Foo");
*
* The assertion chain can be stateful, that means be careful when you reuse
* it. You should never pass around the chain.
*/
public static function that($value, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
{
$assertionChain = new AssertionChain($value, $defaultMessage, $defaultPropertyPath);
return $assertionChain->setAssertionClassName(static::$assertionClass);
}
/**
* Start validation on a set of values, returns {@link AssertionChain}.
*
* @param mixed $values
* @param string|callable|null $defaultMessage
* @param string|null $defaultPropertyPath
*
* @return AssertionChain
*/
public static function thatAll($values, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
{
return static::that($values, $defaultMessage, $defaultPropertyPath)->all();
}
/**
* Start validation and allow NULL, returns {@link AssertionChain}.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
* @param string|null $defaultPropertyPath
*
* @return AssertionChain
*/
public static function thatNullOr($value, $defaultMessage = null, string $defaultPropertyPath = null): AssertionChain
{
return static::that($value, $defaultMessage, $defaultPropertyPath)->nullOr();
}
/**
* Create a lazy assertion object.
*
* @return LazyAssertion
*/
public static function lazy(): LazyAssertion
{
$lazyAssertion = new LazyAssertion();
return $lazyAssertion
->setAssertClass(\get_called_class())
->setExceptionClass(static::$lazyAssertionExceptionClass);
}
}

2825
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/Assertion.php
File diff suppressed because it is too large
View File

254
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionChain.php

@ -0,0 +1,254 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
use LogicException;
use ReflectionClass;
/**
* Chaining builder for assertions.
*
* @author Benjamin Eberlei <kontakt@beberlei.de>
*
* @method AssertionChain alnum(string|callable $message = null, string $propertyPath = null) Assert that value is alphanumeric.
* @method AssertionChain base64(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
* @method AssertionChain between(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater or equal than a lower limit, and less than or equal to an upper limit.
* @method AssertionChain betweenExclusive(mixed $lowerLimit, mixed $upperLimit, string|callable $message = null, string $propertyPath = null) Assert that a value is greater than a lower limit, and less than an upper limit.
* @method AssertionChain betweenLength(int $minLength, int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string length is between min and max lengths.
* @method AssertionChain boolean(string|callable $message = null, string $propertyPath = null) Assert that value is php boolean.
* @method AssertionChain choice(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices.
* @method AssertionChain choicesNotEmpty(array $choices, string|callable $message = null, string $propertyPath = null) Determines if the values array has every choice as key and that this choice has content.
* @method AssertionChain classExists(string|callable $message = null, string $propertyPath = null) Assert that the class exists.
* @method AssertionChain contains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string contains a sequence of chars.
* @method AssertionChain count(int $count, string|callable $message = null, string $propertyPath = null) Assert that the count of countable is equal to count.
* @method AssertionChain date(string $format, string|callable $message = null, string $propertyPath = null) Assert that date is valid and corresponds to the given format.
* @method AssertionChain defined(string|callable $message = null, string $propertyPath = null) Assert that a constant is defined.
* @method AssertionChain digit(string|callable $message = null, string $propertyPath = null) Validates if an integer or integerish is a digit.
* @method AssertionChain directory(string|callable $message = null, string $propertyPath = null) Assert that a directory exists.
* @method AssertionChain e164(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid E164 Phone Number.
* @method AssertionChain email(string|callable $message = null, string $propertyPath = null) Assert that value is an email address (using input_filter/FILTER_VALIDATE_EMAIL).
* @method AssertionChain endsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string ends with a sequence of chars.
* @method AssertionChain eq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are equal (using ==).
* @method AssertionChain eqArraySubset(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that the array contains the subset.
* @method AssertionChain extensionLoaded(string|callable $message = null, string $propertyPath = null) Assert that extension is loaded.
* @method AssertionChain extensionVersion(string $operator, mixed $version, string|callable $message = null, string $propertyPath = null) Assert that extension is loaded and a specific version is installed.
* @method AssertionChain false(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean False.
* @method AssertionChain file(string|callable $message = null, string $propertyPath = null) Assert that a file exists.
* @method AssertionChain float(string|callable $message = null, string $propertyPath = null) Assert that value is a php float.
* @method AssertionChain greaterOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater or equal than given limit.
* @method AssertionChain greaterThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is greater than given limit.
* @method AssertionChain implementsInterface(string $interfaceName, string|callable $message = null, string $propertyPath = null) Assert that the class implements the interface.
* @method AssertionChain inArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is in array of choices. This is an alias of Assertion::choice().
* @method AssertionChain integer(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer.
* @method AssertionChain integerish(string|callable $message = null, string $propertyPath = null) Assert that value is a php integer'ish.
* @method AssertionChain interfaceExists(string|callable $message = null, string $propertyPath = null) Assert that the interface exists.
* @method AssertionChain ip(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 or IPv6 address.
* @method AssertionChain ipv4(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv4 address.
* @method AssertionChain ipv6(int $flag = null, string|callable $message = null, string $propertyPath = null) Assert that value is an IPv6 address.
* @method AssertionChain isArray(string|callable $message = null, string $propertyPath = null) Assert that value is an array.
* @method AssertionChain isArrayAccessible(string|callable $message = null, string $propertyPath = null) Assert that value is an array or an array-accessible object.
* @method AssertionChain isCallable(string|callable $message = null, string $propertyPath = null) Determines that the provided value is callable.
* @method AssertionChain isCountable(string|callable $message = null, string $propertyPath = null) Assert that value is countable.
* @method AssertionChain isInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is instance of given class-name.
* @method AssertionChain isJsonString(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid json string.
* @method AssertionChain isObject(string|callable $message = null, string $propertyPath = null) Determines that the provided value is an object.
* @method AssertionChain isResource(string|callable $message = null, string $propertyPath = null) Assert that value is a resource.
* @method AssertionChain isTraversable(string|callable $message = null, string $propertyPath = null) Assert that value is an array or a traversable object.
* @method AssertionChain keyExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array.
* @method AssertionChain keyIsset(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object using isset().
* @method AssertionChain keyNotExists(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key does not exist in an array.
* @method AssertionChain length(int $length, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string has a given length.
* @method AssertionChain lessOrEqualThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less or equal than given limit.
* @method AssertionChain lessThan(mixed $limit, string|callable $message = null, string $propertyPath = null) Determines if the value is less than given limit.
* @method AssertionChain max(mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that a number is smaller as a given limit.
* @method AssertionChain maxCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at most $count elements.
* @method AssertionChain maxLength(int $maxLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string value is not longer than $maxLength chars.
* @method AssertionChain methodExists(mixed $object, string|callable $message = null, string $propertyPath = null) Determines that the named method is defined in the provided object.
* @method AssertionChain min(mixed $minValue, string|callable $message = null, string $propertyPath = null) Assert that a value is at least as big as a given limit.
* @method AssertionChain minCount(int $count, string|callable $message = null, string $propertyPath = null) Assert that the countable have at least $count elements.
* @method AssertionChain minLength(int $minLength, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that a string is at least $minLength chars long.
* @method AssertionChain noContent(string|callable $message = null, string $propertyPath = null) Assert that value is empty.
* @method AssertionChain notBlank(string|callable $message = null, string $propertyPath = null) Assert that value is not blank.
* @method AssertionChain notContains(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string does not contains a sequence of chars.
* @method AssertionChain notEmpty(string|callable $message = null, string $propertyPath = null) Assert that value is not empty.
* @method AssertionChain notEmptyKey(string|int $key, string|callable $message = null, string $propertyPath = null) Assert that key exists in an array/array-accessible object and its value is not empty.
* @method AssertionChain notEq(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not equal (using ==).
* @method AssertionChain notInArray(array $choices, string|callable $message = null, string $propertyPath = null) Assert that value is not in array of choices.
* @method AssertionChain notIsInstanceOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is not instance of given class-name.
* @method AssertionChain notNull(string|callable $message = null, string $propertyPath = null) Assert that value is not null.
* @method AssertionChain notRegex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value does not match a regex.
* @method AssertionChain notSame(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are not the same (using ===).
* @method AssertionChain null(string|callable $message = null, string $propertyPath = null) Assert that value is null.
* @method AssertionChain numeric(string|callable $message = null, string $propertyPath = null) Assert that value is numeric.
* @method AssertionChain objectOrClass(string|callable $message = null, string $propertyPath = null) Assert that the value is an object, or a class that exists.
* @method AssertionChain phpVersion(mixed $version, string|callable $message = null, string $propertyPath = null) Assert on PHP version.
* @method AssertionChain propertiesExist(array $properties, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the properties all exist.
* @method AssertionChain propertyExists(string $property, string|callable $message = null, string $propertyPath = null) Assert that the value is an object or class, and that the property exists.
* @method AssertionChain range(mixed $minValue, mixed $maxValue, string|callable $message = null, string $propertyPath = null) Assert that value is in range of numbers.
* @method AssertionChain readable(string|callable $message = null, string $propertyPath = null) Assert that the value is something readable.
* @method AssertionChain regex(string $pattern, string|callable $message = null, string $propertyPath = null) Assert that value matches a regex.
* @method AssertionChain same(mixed $value2, string|callable $message = null, string $propertyPath = null) Assert that two values are the same (using ===).
* @method AssertionChain satisfy(callable $callback, string|callable $message = null, string $propertyPath = null) Assert that the provided value is valid according to a callback.
* @method AssertionChain scalar(string|callable $message = null, string $propertyPath = null) Assert that value is a PHP scalar.
* @method AssertionChain startsWith(string $needle, string|callable $message = null, string $propertyPath = null, string $encoding = 'utf8') Assert that string starts with a sequence of chars.
* @method AssertionChain string(string|callable $message = null, string $propertyPath = null) Assert that value is a string.
* @method AssertionChain subclassOf(string $className, string|callable $message = null, string $propertyPath = null) Assert that value is subclass of given class-name.
* @method AssertionChain true(string|callable $message = null, string $propertyPath = null) Assert that the value is boolean True.
* @method AssertionChain url(string|callable $message = null, string $propertyPath = null) Assert that value is an URL.
* @method AssertionChain uuid(string|callable $message = null, string $propertyPath = null) Assert that the given string is a valid UUID.
* @method AssertionChain version(string $operator, string $version2, string|callable $message = null, string $propertyPath = null) Assert comparison of two versions.
* @method AssertionChain writeable(string|callable $message = null, string $propertyPath = null) Assert that the value is something writeable.
*/
class AssertionChain
{
/**
* @var mixed
*/
private $value;
/**
* @var string|callable|null
*/
private $defaultMessage;
/**
* @var string|null
*/
private $defaultPropertyPath;
/**
* Return each assertion as always valid.
*
* @var bool
*/
private $alwaysValid = false;
/**
* Perform assertion on every element of array or traversable.
*
* @var bool
*/
private $all = false;
/** @var string|Assertion Class to use for assertion calls */
private $assertionClassName = 'Assert\Assertion';
/**
* AssertionChain constructor.
*
* @param mixed $value
* @param string|callable|null $defaultMessage
* @param string|null $defaultPropertyPath
*/
public function __construct($value, $defaultMessage = null, string $defaultPropertyPath = null)
{
$this->value = $value;
$this->defaultMessage = $defaultMessage;
$this->defaultPropertyPath = $defaultPropertyPath;
}
/**
* Call assertion on the current value in the chain.
*
* @param string $methodName
* @param array $args
*
* @return AssertionChain
*/
public function __call($methodName, $args): AssertionChain
{
if (true === $this->alwaysValid) {
return $this;
}
if (!\method_exists($this->assertionClassName, $methodName)) {
throw new \RuntimeException("Assertion '".$methodName."' does not exist.");
}
$reflClass = new ReflectionClass($this->assertionClassName);
$method = $reflClass->getMethod($methodName);
\array_unshift($args, $this->value);
$params = $method->getParameters();
foreach ($params as $idx => $param) {
if (isset($args[$idx])) {
continue;
}
if ('message' == $param->getName()) {
$args[$idx] = $this->defaultMessage;
}
if ('propertyPath' == $param->getName()) {
$args[$idx] = $this->defaultPropertyPath;
}
}
if ($this->all) {
$methodName = 'all'.$methodName;
}
\call_user_func_array([$this->assertionClassName, $methodName], $args);
return $this;
}
/**
* Switch chain into validation mode for an array of values.
*
* @return AssertionChain
*/
public function all(): AssertionChain
{
$this->all = true;
return $this;
}
/**
* Switch chain into mode allowing nulls, ignoring further assertions.
*
* @return AssertionChain
*/
public function nullOr(): AssertionChain
{
if (null === $this->value) {
$this->alwaysValid = true;
}
return $this;
}
/**
* @param string $className
*
* @return $this
*/
public function setAssertionClassName($className): AssertionChain
{
if (!\is_string($className)) {
throw new LogicException('Exception class name must be passed as a string');
}
if (Assertion::class !== $className && !\is_subclass_of($className, Assertion::class)) {
throw new LogicException($className.' is not (a subclass of) '.Assertion::class);
}
$this->assertionClassName = $className;
return $this;
}
}

35
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/AssertionFailedException.php

@ -0,0 +1,35 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
use Throwable;
interface AssertionFailedException extends Throwable
{
/**
* @return string|null
*/
public function getPropertyPath();
/**
* @return mixed
*/
public function getValue();
/**
* @return array
*/
public function getConstraints(): array;
}

76
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/InvalidArgumentException.php

@ -0,0 +1,76 @@
<?php
/**
* Assert
*
* LICENSE
*
* This source file is subject to the MIT license that is bundled
* with this package in the file LICENSE.txt.
* If you did not receive a copy of the license and are unable to
* obtain it through the world-wide-web, please send an email
* to kontakt@beberlei.de so I can send you a copy immediately.
*/
namespace Assert;
class InvalidArgumentException extends \InvalidArgumentException implements AssertionFailedException
{
/**
* @var string|null
*/
private $propertyPath;
/**
* @var mixed
*/
private $value;
/**
* @var array
*/
private $constraints;
public function __construct($message, $code, string $propertyPath = null, $value = null, array $constraints = [])
{
parent::__construct($message, $code);
$this->propertyPath = $propertyPath;
$this->value = $value;
$this->constraints = $constraints;
}
/**
* User controlled way to define a sub-property causing
* the failure of a currently asserted objects.
*
* Useful to transport information about the nature of the error
* back to higher layers.
*
* @return string|null
*/
public function getPropertyPath()
{
return $this->propertyPath;
}
/**
* Get the value that caused the assertion to fail.
*
* @return mixed
*/
public function getValue()
{
return $this->value;
}
/**
* Get the constraints that applied to the failed assertion.
*
* @return array
*/
public function getConstraints(): array
{
return $this->constraints;
}
}

230
lam/lib/3rdParty/composer/beberlei/assert/lib/Assert/LazyAssertion.php

@ -0,0 +1,230 @@
<?php
/**
* Assert