diff --git a/.coveralls.yml b/.coveralls.yml new file mode 100644 index 00000000..cb6cdeb2 --- /dev/null +++ b/.coveralls.yml @@ -0,0 +1,7 @@ +service_name: github + +src_dir: lib + +coverage_clover: tests/build/logs/clover.xml + +json_path: tests/build/logs/coveralls-upload.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..c5ae3d5c --- /dev/null +++ b/.gitattributes @@ -0,0 +1,13 @@ +/.coveralls.yml export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.travis.yml export-ignore +/demo-old export-ignore +/demo2 export-ignore +/docs export-ignore +/endpoints export-ignore +/locale export-ignore +/tests export-ignore +/phpdoc.xml export-ignore +/_toolkit_loader.php +/compatibility.php diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 00000000..ac0a9f6c --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1,3 @@ +# These are supported funding model platforms + +github: [SAML-Toolkits] diff --git a/.github/workflows/php-package.yml b/.github/workflows/php-package.yml new file mode 100644 index 00000000..4f12009f --- /dev/null +++ b/.github/workflows/php-package.yml @@ -0,0 +1,57 @@ +# This workflow will install PHP dependencies, run tests and lint with a variety of PHP versions +# For more information see: https://github.com/marketplace/actions/setup-php-action + +name: php-saml package + +on: + push: + branches: [ master, 3.*, 4.* ] + pull_request: + branches: [ master, 3.*, 4.* ] + +jobs: + test: + runs-on: ${{ matrix.operating-system }} + strategy: + fail-fast: false + matrix: + operating-system: ['ubuntu-latest'] + php-versions: [5.3, 5.4, 5.5, 5.6, 7.0, 7.1] + steps: + - name: Setup PHP, with composer and extensions + uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php + with: + php-version: ${{ matrix.php-versions }} + extensions: mbstring, intl, mcrypt, xml + tools: composer:v2 + ini-values: post_max_size=256M, max_execution_time=180 + coverage: xdebug + + - name: Set git to use LF + run: | + git config --global core.autocrlf false + git config --global core.eol lf + + - uses: actions/checkout@v2 + + - name: Validate composer.json and composer.lock + run: composer validate + + - name: Install Composer dependencies + run: | + composer self-update + composer install --prefer-source --no-interaction + + - name: Syntax check PHP + run: | + php vendor/bin/phpcpd --exclude tests --exclude vendor . + php vendor/bin/phploc . --exclude vendor + php vendor/bin/phploc lib/. + mkdir -p tests/build/dependences + php vendor/bin/pdepend --summary-xml=tests/build/logs/dependence-summary.xml --jdepend-chart=tests/build/dependences/jdepend.svg --overview-pyramid=tests/build/dependences/pyramid.svg lib/. + + - name: PHP Code Sniffer + run: php vendor/bin/phpcs --standard=tests/ZendModStandard lib/Saml2 demo1 demo2 demo-old endpoints tests/src + + - name: Run unit tests + run: vendor/bin/phpunit --verbose --debug diff --git a/.gitignore b/.gitignore index bf9dfdce..b8f59256 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,15 @@ *.swp +*~ .DS_Store +/settings.php +/demo1/settings.php +/demo-old/settings.php +/certs/sp.key +/certs/sp.crt +/certs/sp_new.crt +/certs/metadata.key +/certs/metadata.crt +/tests/build +/vendor +/composer.lock +/.idea diff --git a/CHANGELOG b/CHANGELOG new file mode 100644 index 00000000..8ddb5764 --- /dev/null +++ b/CHANGELOG @@ -0,0 +1,294 @@ +CHANGELOG +========= + +v.2.21.0 +* [#619](https://github.com/SAML-Toolkits/php-saml/pull/619) Add Parameter checking on validateBinarySign, inspired on CVE-2025-27773 +* [#603](https://github.com/SAML-Toolkits/php-saml/issues/603) Fix typo in ignoreValidUntil that breaks metadata. Add parameter to exclude validUntil on Settings getSPMetadata +* [#594](https://github.com/SAML-Toolkits/php-saml/pull/594) Add support for encrypted name id in encrypted assertion +* Fix buildWithBaseURLPath +* Doc fix typo +* Remove Travis CI references + +v.2.20.0 +* [#586](https://github.com/SAML-Toolkits/php-saml/pull/586) IdPMetadataParser::parseRemoteXML - Add argument for setting whether to validate peer SSL certificate +* [#585](https://github.com/SAML-Toolkits/php-saml/pull/585) Declare conditional return types +* Make Saml2\Auth can accept a param $spValidationOnly +* [#577](https://github.com/SAML-Toolkits/php-saml/pull/577) Allow empty NameID value when no strict or wantNameId is false +* [#570](https://github.com/SAML-Toolkits/php-saml/pull/570) Support X509 cert comments +* [#569](https://github.com/SAML-Toolkits/php-saml/pull/569) Add parameter to exclude validUntil on SP Metadata XML +* [#551](https://github.com/SAML-Toolkits/php-saml/pull/551) Fix compatibility with proxies that extends HTTP_X_FORWARDED_HOST +* [#487](https://github.com/SAML-Toolkits/php-saml/issues/487) Enable strict check on in_array method +* Fix typos on readme. +* [#480](https://github.com/SAML-Toolkits/php-saml/pull/480) Fix typo on SPNameQualifier mismatch error message +* Add $spValidationOnly param to Auth +* Update xmlseclibs (3.1.2 without AES-GCM and OAEP support) +* Add warning about Open Redirect and Reply attacks +* Add warning about the use of IdpMetadataParser class. If Metadata URLs + are provided by 3rd parties, the URL inputs MUST be validated to avoid issues like SSRF +* Update dependencies +* Fix test payloads +* Remove references to OneLogin. + +v.2.19.1 +* [#467](https://github.com/onelogin/php-saml/issues/467) Fix bug on getSelfRoutedURLNoQuery method + +v.2.19.0 +* [#412](https://github.com/onelogin/php-saml/pull/412) Empty instead of unset the $_SESSION variable +* [#433](https://github.com/onelogin/php-saml/issues/443) Fix Incorrect Destination in LogoutResponse when using responseUrl #443 +* Add support for SMARTCARD_PKI and RSA_TOKEN Auth Contexts +* Support Statements with Attribute elements with the same name enabling the allowRepeatAttributeName setting +* Get lib path dynamically +* Check for x509Cert of the IdP when loading settings, even if the security index was not provided + +v.2.18.1 +* Add setSchemasPath to Auth class and fix backward compatibility + +v.2.18.0 +* Support rejecting unsolicited SAMLResponses. +* Support stric destination matching. +* Reject SAMLResponse if requestID was provided to the validotr but the InResponseTo attributeof the SAMLResponse is missing +* Check destination against the getSelfURLNoQuery as well on LogoutRequest and LogoutResponse as we do on Response +* Improve getSelfRoutedURLNoQuery method +* Only add responseUrl to the settings if ResponseLocation present in the IdPMetadataParser +* Remove use of $_GET on static method validateBinarySign +* Fix error message when Assertion and NameId are both encrypted (not supported) + +v.2.17.1 +* Update xmlseclibs to 3.0.4 +* Remove Comparison atribute from RequestedAuthnContext when setting has empty value + +v.2.17.0 +* Set true as the default value for strict setting +* Support 'x509cert' and 'privateKey' on signMetadata security settings +* Relax comparison of false on SignMetadata +* Fix CI + +v.2.16.0 +* Support SLO ResponseLocation +* [#344](https://github.com/onelogin/php-saml/issues/344) Raise errors on IdPMetadataParser::parseRemoteXML and IdPMetadataParser::parseFileXML +* Adjusted acs endpoint to extract NameQualifier and SPNameQualifier from SAMLResponse. Adjusted single logout service to provide NameQualifier and SPNameQualifier to logout method. Add getNameIdNameQualifier to Auth and SamlResponse. Extend logout method from Auth and LogoutRequest constructor to support SPNameQualifier parameter. Align LogoutRequest constructor with SAML specs +* Add support for Subjects on AuthNRequests by the new parameter +* Set strict=true on config examples + +v.2.15.0 +* Security improvement suggested by Nils Engelbertz to prevent DDOS by expansion of internally defined entities (XEE) +* Fix bug on settings_example.php + +v.2.14.0 +* Add parameter to the decryptElement method to make optional the formatting +* [#283](https://github.com/onelogin/php-saml/pull/283) New method of importing a decrypted assertion into the XML document to replace the EncryptedAssertion. Fix signature issues on Signed Encrypted Assertions with default namespace +* Allow the getSPMetadata() method to always include the encryption Key Descriptor +* Change some Fatal Error to Exceptions +* [#265](https://github.com/onelogin/php-saml/issues/265) Support parameters at getSPMetadata method +* Avoid calling static method using this + +v.2.13.0 +* Update xmlseclibs with some fixes. +* Add extra protection verifying the Signature algorithm used on SignedInfo element, not only rely on the xmlseclibs verify / verifySignature methods. +* Add getAttributesWithFriendlyName method which returns the set of SAML attributes indexed by FriendlyName +* Fix bug on parseRemoteXML and parseFileXML. Internal calls to parseXML missed the desiredNameIdFormat parameter + +v.2.12.0 +* Improve Time management. Use DateTime/DateTimeZone classes. +* Escape error messages in debug mode +* Improve phpdoc +* Add an extra filter to the url to be used on redirection + +* [#242](https://github.com/onelogin/php-saml/pull/242) Document that SHA-1 must not be used +* [#250](https://github.com/onelogin/php-saml/pull/250) Fixed issue with IdPMetadataParser only keeping 1 certificate when multiple certificates of a single type were provided. +* [#263](https://github.com/onelogin/php-saml/issues/263) Fix incompatibility with ADFS on SLO. When on php saml settings NameID Format is set as unspecified but the SAMLResponse has no NameID Format, no NameID Format should be specified on LogoutRequest. + +v.2.11.0 +* [#236](https://github.com/onelogin/php-saml/pull/236) Exclude unnecessary files from Composer production downloads +* [#226](https://github.com/onelogin/php-saml/pull/226) Add possibility to handle nameId NameQualifier attribute in SLO Request +* Improve logout documentation on Readme. +* Improve multi-certificate support + +v.2.10.7 +* Fix IdPMetadataParser. The SingleLogoutService retrieved method was wrong +* [#201](https://github.com/onelogin/php-saml/issues/201) Fix issues with SP entity_id, acs url and sls url that contains & + +v.2.10.6 +* [#206](https://github.com/onelogin/php-saml/pull/206)Be able to register future SP x509cert on the settings and publish it on SP metadata +* [#206](https://github.com/onelogin/php-saml/pull/206) Be able to register more than 1 Identity Provider x509cert, linked with an specific use (signing or encryption) +* [#206](https://github.com/onelogin/php-saml/pull/206) Support the ability to parse IdP XML metadata (remote url or file) and be able to inject the data obtained on the settings. + +v.2.10.5 +* Be able to get at the auth object the last processed ID +* Improve NameID Format support +* Reset errorReason attribute of the auth object after each Process method +* Validate serial number as string to work around libxml2 limitation +* Make the Issuer on the Response Optional + +v.2.10.4 +* [+](https://github.com/onelogin/php-saml/commit/949359f5cad5e1d085c4e5447d9aa8f49a6e82a1) Security update for signature validation on LogoutRequest/LogoutResponse +* [#192](https://github.com/onelogin/php-saml/pull/192) Added ability to configure DigestAlgorithm in settings +* [#183](https://github.com/onelogin/php-saml/pull/183) Fix strpos bug when decrypting assertions +* [#186](https://github.com/onelogin/php-saml/pull/186) Improve info on entityId validation Exception +* [#188](https://github.com/onelogin/php-saml/pull/188) Fixed issue with undefined constant of UNEXPECTED_SIGNED_ELEMENT +* Read ACS binding on AuthNRequest builder from settings +* Be able to relax Destination validation on SAMLResponses and let this + attribute to be empty with the 'relaxDestinationValidation' setting + +v.2.10.3 +* Implement a more specific exception class for handling some validation errors +* Minor changes on time validation/exceptions +* Add hooks to retrieve last-sent and last-received requests and responses +* Improve/Fix tests +* Add DigestAlgorithm support on addSign +* [#177](https://github.com/onelogin/php-saml/pull/177) Add error message for bad OneLogin_Saml2_Settings argument + +v.2.10.2 +* [#175](https://github.com/onelogin/php-saml/pull/175) Allow overriding of host, port, protocol and url path for URL building +* [#173](https://github.com/onelogin/php-saml/pull/173) Provide better support to NameIdFormat +* Fix another issue on Assertion Signature validation when the assertion contains no namespace, container has saml2 namespace and it was encrypted + +v.2.10.1 +* Fix error message on SignMetadata process +* Fix issue on Assertion Signature validation when the assertion contains no namespace and it was encrypted + +v.2.10.0 +* Several security improvements: + * Conditions element required and unique. + * AuthnStatement element required and unique. + * SPNameQualifier must math the SP EntityID + * Reject saml:Attribute element with same “Name” attribute + * Reject empty nameID + * Require Issuer element. (Must match IdP EntityID). + * Destination value can't be blank (if present must match ACS URL). + * Check that the EncryptedAssertion element only contains 1 Assertion element. +* Improve Signature validation process +* AttributeConsumingService support +* Support lowercase Urlencoding (ADFS compatibility). +* [#154](https://github.com/onelogin/php-saml/pull/154) getSelfHost no longer returns a port number +* [#156](https://github.com/onelogin/php-saml/pull/156) Use correct host on response destination fallback check +* [#158](https://github.com/onelogin/php-saml/pull/158) NEW Control usage of X-Forwarded-* headers +* Fix issue with buildRequestSignature. Added RelayState to the SignQuery only if is not null. +* Add Signature Wrapping prevention Test +* Improve _decryptAssertion in order to take care of Assertions with problems with namespaces +* Improve documentation + +v.2.9.1 +....... +* [134](https://github.com/onelogin/php-saml/pull/134) PHP7 production settings compiles out assert(), throw an exception explicitly +* [132](https://github.com/onelogin/php-saml/pull/132) Add note for "wantAssertionsEncrypted" +* Update copyright on LICENSE + +v.2.9.0 +------- +* Change the decrypt assertion process. +* Add 2 extra validations to prevent Signature wrapping attacks. +* Remove reference to wrong NameIDFormat: urn:oasis:names:tc:SAML:2.0:nameid-format:unspecified should be urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified +* [128](https://github.com/onelogin/php-saml/pull/128) Test php7 and upgrade phpunit +* Update Readme with more descriptive requestedAuthnContext description and Security Guidelines + +v.2.8.0 +------- +* Make NameIDPolicy of AuthNRequest optional +* Make nameID requirement on SAMLResponse optional +* Fix empty URI support +* Symmetric encryption key support +* Add more Auth Context options to the constant class +* Fix DSA_SHA1 constant on xmlseclibs +* Set none requestedAuthnContext as default behaviour +* Update xmlseclibs lib +* Improve formatPrivateKey method +* Fix bug when signing metadata, the SignatureMethod was not provided +* Fix getter for lastRequestID parameter in OneLogin_Saml2_Auth class +* Add $wantEncrypted parameter on addX509KeyDescriptors method that will allow to set KeyDescriptor[use='encryption'] if wantNameIdEncrypted or wantAssertionsEncrypted enabled +* Add $stay parameter on redirectTo method. (login/logout supports $stay but I forgot add this on previous 2.7.0 version) +* Improve code style + +v.2.7.0 +------- +* Trim acs, slo and issuer urls. +* Fix PHP 7 error (used continue outside a loop/switch). +* Fix bug on organization element of the SP metadata builder. +* Fix typos on documentation. Fix ALOWED Misspell. +* Be able to extract RequestID. Add RequestID validation on demo1. +* Add $stay parameter to login, logout and processSLO method. + +v.2.6.1 +------- +* Fix bug on cacheDuration of the Metadata XML generated. +* Make SPNameQualifier optional on the generateNameId method. Avoid the use of SPNameQualifier when generating the NameID on the LogoutRequest builder. +* Allows the authn comparison attribute to be set via config. +* Retrieve Session Timeout after processResponse with getSessionExpiration(). +* Improve readme readability. +* Allow single log out to work for applications not leveraging php session_start. Added a callback parameter in order to close the session at processSLO. + +v.2.6.0 +------- +* Set NAMEID_UNSPECIFIED as default NameIDFormat to prevent conflicts with IdPs that don't support NAMEID_PERSISTENT. +* Now the SP is able to select the algorithm to be used on signatures (DSA_SHA1, RSA_SHA1, RSA_SHA256, RSA_SHA384, RSA_SHA512). +* Change visibility of _decryptAssertion to protected. +* Update xmlseclibs library. +* Handle valid but uncommon dsig block with no URI in the reference. +* login, logout and processSLO now return ->redirectTo instead of just call it. +* Split the setting check methods. Now 1 method for IdP settings and other for SP settings. +* Let the setting object to avoid the IdP setting check. required if we want to publish SP SAML Metadata when the IdP data is still not provided. + +v.2.5.0 +------- +* Do accessible the ID of the object Logout Request (id attribute). +* Add note about the fact that PHP 5.3 is unsupported. +* Add fingerprint algorithm support. +* Add dependences to composer. + +v.2.4.0 +------- +* Fix wrong element order in generated metadata. +* Added SLO with nameID and SessionIndex in demo1. +* Improve isHTTPS method in order to support HTTP_X_FORWARDED_PORT. +* Set optional the XMLvalidation (enable/disable it with wantXMLValidation security setting). + +v.2.3.0 +------- +* Resolve namespace problem. Some IdPs uses saml2p:Response and saml2:Assertion instead of samlp:Response saml:Assertion. +* Improve test and documentation. +* Improve ADFS compatibility. +* Remove unnecessary XSDs files. +* Make available the reason for the saml message invalidation. +* Adding ability to set idp cert once the Setting object initialized. +* Fix status info issue. +* Reject SAML Response if not signed and strict = false. +* Support NameId and SessionIndex in LogoutRequest. +* Add ForceAuh and IsPassive support. + +v.2.2.0 +------- +* Fix bug with Encrypted nameID on LogoutRequest. +* Fixed usability bug. SP will inform about AuthFail status after process a Response. +* Added SessionIndex support on LogoutRequest, and know is accessible from the Auth class. +* LogoutRequest and LogoutResponse classes now accept non deflated xml. +* Improved the XML metadata/ Decrypted Assertion output. (prettyprint). +* Fix bug in formatPrivateKey method, the key could be not RSA. +* Explicit warning message for signed element problem. +* Decrypt method improved. +* Support more algorithm at the SigAlg in the Signed LogoutRequests and LogoutResponses +* AuthNRequest now stores ID (it can be retrieved later). +* Fixed a typo on the 'NameIdPolicy' attribute that appeared at the README and settings_example file. + + +v.2.1.0 +------- + +* The isValid method of the Logout Request is now non-static. (affects processSLO method of Auth.php). +* Logout Request constructor now accepts encoded logout requests. +* Now after validate a message, if fails a method getError of the object will return the cause. +* Fix typos. +* Added extra parameters option to login and logout methods. +* Improve Test (new test, use the new getError method for testing). +* Bugfix namespace problem when getting Attributes. + + +v.2.0.0 +------- + +* New PHP SAML Toolkit (SLO, Sign, Encryptation). + + +v.1.0.0 +------- + +* Old PHP SAML Toolkit. diff --git a/LICENSE b/LICENSE index a4a8af0e..dbbca9c6 100644 --- a/LICENSE +++ b/LICENSE @@ -1,24 +1,23 @@ -Copyright (c) 2010, OneLogin, Inc. -All rights reserved. +Copyright (c) 2010-2016 OneLogin, Inc. -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, +copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the +Software is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. -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 ONELOGIN, INC. 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. \ No newline at end of file diff --git a/README b/README deleted file mode 100644 index 723af94d..00000000 --- a/README +++ /dev/null @@ -1,9 +0,0 @@ -The files in demo are sample code to help -demonstrate how this library should work. In order to use them, you can -unpack this library in your website directory. - -You will need to modify the settings.php file to set the proper URLs and -x509 certificate. - -There is more information in this post: -http://support.onelogin.com/entries/268420-saml-toolkit-for-php diff --git a/README.md b/README.md new file mode 100644 index 00000000..8c6407af --- /dev/null +++ b/README.md @@ -0,0 +1,1745 @@ +# SAML PHP Toolkit + +[![php-saml package](https://github.com/SAML-Toolkits/php-saml/actions/workflows/php-package.yml/badge.svg?branch=master)](https://github.com/SAML-Toolkits/php-saml/actions/workflows/php-package.yml) [![Coverage Status](https://coveralls.io/repos/github/SAML-Toolkits/php-saml/badge.svg?branch=master)](https://coveralls.io/github/SAML-Toolkits/php-saml?branch=master) ![Packagist Dependency Version (specify version)](https://img.shields.io/packagist/dependency-v/onelogin/php-saml/php?version=2.19.1) [![License](https://poser.pugx.org/onelogin/php-saml/license.png)](https://packagist.org/packages/onelogin/php-saml) ![Packagist Downloads](https://img.shields.io/packagist/dm/onelogin/php-saml) ![Packagist Downloads](https://img.shields.io/packagist/dt/onelogin/php-saml?label=Total%20downloads) + +Add SAML support to your PHP software using this library. + + +**The 3.X branch is compatible with PHP 7.0, PHP 7.1, PHP 7.2 , so if you are using that PHP version, use it and not the 2.X or the master branch** + +**The 4.X branch is compatible with PHP >= 7.3 and PHP 8.X** + +Warning +------- + +Version 2.18.0 introduces the 'rejectUnsolicitedResponsesWithInResponseTo' setting parameter, by default disabled, that will allow invalidate unsolicited SAMLResponse. This version as well will reject SAMLResponse if requestId was provided to the validator but the SAMLResponse does not contain a InResponseTo attribute. And an additional setting parameter 'destinationStrictlyMatches', by default disabled, that will force that the Destination URL should strictly match to the address that process the SAMLResponse. + +Version 2.17.1 updates xmlseclibs to 3.0.4 (CVE-2019-3465), but php-saml was not directly affected since it implements additional checks that prevent to exploit that vulnerability. + +Version 2.17.0 sets strict mode active by default + +Update php-saml to 2.15.0, this version includes a security patch related to XEE attacks + +php-saml is not affected by [201803-01](https://simplesamlphp.org/security/201803-01) + +Update php-saml to 2.10.4, this version includes a security patch related to +[signature validations on LogoutRequests/LogoutResponses](https://github.com/onelogin/php-saml/commit/949359f5cad5e1d085c4e5447d9aa8f49a6e82a1) + +Update php-saml to 2.10.0, this version includes a security patch that contains extra validations that will prevent signature wrapping attacks. [CVE-2016-1000253](https://github.com/distributedweaknessfiling/DWF-Database-Artifacts/blob/ab8ae6e845eb506fbeb10a7e4ccb379f0b4222ca/DWF/2016/1000253/CVE-2016-1000253.json) + +php-saml < v2.10.0 is vulnerable and allows signature wrapping! + + +Security Guidelines +------------------- + +If you believe you have discovered a security vulnerability in this toolkit, please report it by mail to the maintainer: sixto.martin.garcia+security@gmail.com + + +Why add SAML support to my software? +------------------------------------ + +SAML is an XML-based standard for web browser single sign-on and is defined by +the OASIS Security Services Technical Committee. The standard has been around +since 2002, but lately it is becoming popular due its advantages: + + * **Usability** - One-click access from portals or intranets, deep linking, + password elimination and automatically renewing sessions make life + easier for the user. + * **Security** - Based on strong digital signatures for authentication and + integrity, SAML is a secure single sign-on protocol that the largest + and most security conscious enterprises in the world rely on. + * **Speed** - SAML is fast. One browser redirect is all it takes to securely + sign a user into an application. + * **Phishing Prevention** - If you don’t have a password for an app, you + can’t be tricked into entering it on a fake login page. + * **IT Friendly** - SAML simplifies life for IT because it centralizes + authentication, provides greater visibility and makes directory + integration easier. + * **Opportunity** - B2B cloud vendor should support SAML to facilitate the + integration of their product. + + +General description +------------------- + +SAML PHP toolkit let you build a SP (Service Provider) over +your PHP application and connect it to any IdP (Identity Provider). + +Supports: + + * SSO and SLO (SP-Initiated and IdP-Initiated). + * Assertion and nameId encryption. + * Assertion signature. + * Message signature: AuthNRequest, LogoutRequest, LogoutResponses. + * Enable an Assertion Consumer Service endpoint. + * Enable a Single Logout Service endpoint. + * Publish the SP metadata (which can be signed). + +Key features: + + * **saml2int** - Implements the SAML 2.0 Web Browser SSO Profile. + * **Session-less** - Forget those common conflicts between the SP and + the final app, the toolkit delegate session in the final app. + * **Easy to use** - Programmer will be allowed to code high-level and + low-level programming, 2 easy to use APIs are available. + * **Tested** - Thoroughly tested. + * **Popular** - customers use it. Many PHP SAML plugins uses it. + +Integrate your PHP toolkit at OneLogin using this guide: [https://developers.onelogin.com/page/saml-toolkit-for-php](https://developers.onelogin.com/page/saml-toolkit-for-php) + +Installation +------------ + +### Dependencies ### + + * `php >= 5.3.3` and some core extensions like `php-xml`, `php-date`, `php-zlib`. + * `openssl`. Install the openssl library. It handles x509 certificates. + * `mcrypt`. Install that library and its php driver if you're going to handle + encrypted data (`nameID`, `assertions`). + * `curl`. Install that library and its php driver if you plan to use the IdP Metadata parser. + +Since [PHP 5.3 is officially unsupported](http://php.net/eol.php) we recommend you to use a newer PHP version. + +### Code ### + +#### Option 1. clone the repository from github #### + +git clone git@github.com:onelogin/php-saml.git + +#### Option 2. Download from github #### + +The toolkit is hosted on github. You can download it from: + + * Latest release: https://github.com/onelogin/php-saml/releases/latest + * Master repo: https://github.com/onelogin/php-saml/tree/master + +Copy the core of the library inside the php application. (each application has its +structure so take your time to locate the PHP SAML toolkit in the best place). +See the "Guide to add SAML support to my app" to know how. + +Take in mind that the compressed file only contains the main files. +If you plan to play with the demos, use the Option 1. + +#### Option 3. Composer #### + +The toolkit supports [composer](https://getcomposer.org/). You can find the `onelogin/php-saml` package at https://packagist.org/packages/onelogin/php-saml + +In order to import the saml toolkit to your current php project, execute +``` +composer require onelogin/php-saml +``` + +After installation has completed you will find at the `vendor/` folder a new folder named `onelogin` and inside the `php-saml`. Make sure you are including the autoloader provided by composer. It can be found at `vendor/autoload.php`. + +**Important** In this option, the x509 certs must be stored at `vendor/onelogin/php-saml/certs` +and settings file stored at `vendor/onelogin/php-saml`. + +Your settings are at risk of being deleted when updating packages using `composer update` or similar commands. So it is **highly** recommended that instead of using settings files, you pass the settings as an array directly to the constructor (explained later in this document). If you do not use this approach your settings are at risk of being deleted when updating packages using `composer update` or similar commands. + +Compatibility +------------- + +This 2.0 version has a new library. The toolkit is still compatible. + +The old code that you used in order to add SAML support will continue working +with minor changes. You only need to load the files of the `lib/Saml` folder. +(notice that the `compatibility.php` file do that). + +The old-demo folder contains code from an old app that uses the old version of +the toolkit (v.1). Take a look. + +Sometimes the names of the classes of the old code could be a bit different +and if that is your case you must change them for `OneLogin_Saml_Settings`, +`OneLogin_Saml_Response`, `OneLogin_Saml_AuthRequest` or `OneLogin_Saml_Metadata`. + +We recommend that you migrate the old code to the new one to be able to use +the new features that the new library Saml2 carries. + + +Namespaces +---------- + +If you are using the library with a framework like Symfony that contains +namespaces, remember that calls to the class must be done by adding a backslash (`\`) to the +start, for example to use the static method getSelfURLNoQuery use: + + \OneLogin_Saml2_Utils::getSelfURLNoQuery() + + +Security warning +---------------- + +In production, the `strict` parameter **MUST** be set as `"true"` and the +`signatureAlgorithm` and `digestAlgorithm` under `security` must be set to +something other than SHA1 (see https://shattered.io/ ). Otherwise your +environment is not secure and will be exposed to attacks. + +In production also we highly recommended to register on the settings the IdP certificate instead of using the fingerprint method. The fingerprint, is a hash, so at the end is open to a collision attack that can end on a signature validation bypass. Other SAML toolkits deprecated that mechanism, we maintain it for compatibility and also to be used on test environment. + + +### Avoiding Open Redirect attacks ### + +Some implementations uses the RelayState parameter as a way to control the flow when SSO and SLO succeeded. So basically the +user is redirected to the value of the RelayState. + +If you are using Signature Validation on the HTTP-Redirect binding, you will have the RelayState value integrity covered, otherwise, and +on HTTP-POST binding, you can't trust the RelayState so before +executing the validation, you need to verify that its value belong +a trusted and expected URL. + +Read more about Open Redirect [CWE-601](https://cwe.mitre.org/data/definitions/601.html). + + +### Avoiding Replay attacks ### + +A replay attack is basically try to reuse an intercepted valid SAML Message in order to impersonate a SAML action (SSO or SLO). + +SAML Messages have a limited timelife (NotBefore, NotOnOrAfter) that +make harder this kind of attacks, but they are still possible. + +In order to avoid them, the SP can keep a list of SAML Messages or Assertion IDs already validated and processed. Those values only need +to be stored the amount of time of the SAML Message life time, so +we don't need to store all processed message/assertion Ids, but the most recent ones. + +The OneLogin_Saml2_Auth class contains the [getLastRequestID](https://github.com/onelogin/php-saml/blob/f08bc1e8321cc8b855481153a26b9ed57a5201c2/lib/Saml2/Auth.php#L623), [getLastMessageId](https://github.com/onelogin/php-saml/blob/f08bc1e8321cc8b855481153a26b9ed57a5201c2/lib/Saml2/Auth.php#L709) and [getLastAssertionId](https://github.com/onelogin/php-saml/blob/f08bc1e8321cc8b855481153a26b9ed57a5201c2/lib/Saml2/Auth.php#L717) methods to retrieve the IDs + +Checking that the ID of the current Message/Assertion does not exists in the list of the ones already processed will prevent reply +attacks. + + +Getting started +--------------- + +### Knowing the toolkit ### + +The new OneLogin SAML Toolkit contains different folders (`certs`, `endpoints`, +`extlib`, `lib`, `demo`, etc.) and some files. + +Let's start describing the folders: + +#### `certs/` #### + +SAML requires a x509 cert to sign and encrypt elements like `NameID`, `Message`, +`Assertion`, `Metadata`. + +If our environment requires sign or encrypt support, this folder may contain +the x509 cert and the private key that the SP will use: + + * `sp.crt` - The public cert of the SP + * `sp.key` - The private key of the SP + +Or also we can provide those data in the setting file at the `$settings['sp']['x509cert']` +and the `$settings['sp']['privateKey']`. + +Sometimes we could need a signature on the metadata published by the SP, in +this case we could use the x509 cert previously mentioned or use a new x509 +cert: `metadata.crt` and `metadata.key`. + +Use `sp_new.crt` if you are in a key rollover process and you want to +publish that x509 certificate on Service Provider metadata. + +#### `extlib/` #### + +This folder contains the 3rd party libraries that the toolkit uses. At the +moment only uses the `xmlseclibs` (author Robert Richards, BSD Licensed) which +handle the sign and the encryption of xml elements. + + +#### `lib/` #### + +This folder contains the heart of the toolkit, the libraries: + + * `Saml` folder contains a modified version of the toolkit v.1 and allows the + old code to keep working. (This library is provided to maintain + backward compatibility). + * `Saml2` folder contains the new version of the classes and methods that + are described in a later section. + + +#### `doc/` #### + +This folder contains the API documentation of the toolkit. + + +#### `endpoints/` #### + +The toolkit has three endpoints: + + * `metadata.php` - Where the metadata of the SP is published. + * `acs.php` - Assertion Consumer Service. Processes the SAML Responses. + * `sls.php` - Single Logout Service. Processes Logout Requests and Logout + Responses. + +You can use the files provided by the toolkit or create your own endpoints +files when adding SAML support to your applications. Take in mind that those +endpoints files uses the setting file of the toolkit's base folder. + + +#### `locale/` #### + +Locale folder contains some translations: `en_US` and `es_ES` as a proof of concept. +Currently there are no translations but we will eventually localize the messages +and support multiple languages. + + +#### Other important files #### + +* `settings_example.php` - A template to be used in order to create a + settings.php file which contains the basic configuration info of the toolkit. +* `advanced_settings_example.php` - A template to be used in order to create a + advanced_settings.php file which contains extra configuration info related to + the security, the contact person, and the organization associated to the SP. +* `_toolkit_loader.php` - This file load the toolkit libraries (The SAML2 lib). +* `compatibility` - Import that file to make compatible your old code with the + new toolkit (loads the SAML library). + + +#### Miscellaneous #### + +* `tests/` - Contains the unit test of the toolkit. +* `demo1/` - Contains an example of a simple PHP app with SAML support. + Read the `Readme.txt` inside for more info. +* `demo2/` - Contains another example. +* `demo-old/` - Contains an example that uses the code of the older version of the + the toolkit to demonstrate the backwards compatibility. + + +### How it works ### + +#### Settings #### + +First of all we need to configure the toolkit. The SP's info, the IdP's info, +and in some cases, configure advanced security issues like signatures and +encryption. + +There are two ways to provide the settings information: + + * Use a `settings.php` file that we should locate at the base folder of the + toolkit. + * Use an array with the setting data and provide it directly to the + constructor of the class. + + +There is a template file, `settings_example.php`, so you can make a copy of this +file, rename and edit it. + +```php + true, + + // Enable debug mode (to print errors). + 'debug' => false, + + // Set a BaseURL to be used instead of try to guess + // the BaseURL of the view that process the SAML Message. + // Ex http://sp.example.com/ + // http://example.com/sp/ + 'baseurl' => null, + + // Service Provider Data that we are deploying. + 'sp' => array ( + // Identifier of the SP entity (must be a URI) + 'entityId' => '', + // Specifies info about where and how the message MUST be + // returned to the requester, in this case our SP. + 'assertionConsumerService' => array ( + // URL Location where the from the IdP will be returned + 'url' => '', + // SAML protocol binding to be used when returning the + // message. SAML Toolkit supports this endpoint for the + // HTTP-POST binding only. + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', + ), + // If you need to specify requested attributes, set a + // attributeConsumingService. nameFormat, attributeValue and + // friendlyName can be omitted + "attributeConsumingService"=> array( + "serviceName" => "SP test", + "serviceDescription" => "Test Service", + "requestedAttributes" => array( + array( + "name" => "", + "isRequired" => false, + "nameFormat" => "", + "friendlyName" => "", + "attributeValue" => array() + ) + ) + ), + // Specifies info about where and how the message MUST be + // returned to the requester, in this case our SP. + 'singleLogoutService' => array ( + // URL Location where the from the IdP will be returned + 'url' => '', + // SAML protocol binding to be used when returning the + // message. SAML Toolkit supports the HTTP-Redirect binding + // only for this endpoint. + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + ), + // Specifies the constraints on the name identifier to be used to + // represent the requested subject. + // Take a look on lib/Saml2/Constants.php to see the NameIdFormat supported. + 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', + // Usually x509cert and privateKey of the SP are provided by files placed at + // the certs folder. But we can also provide them with the following parameters + 'x509cert' => '', + 'privateKey' => '', + + /* + * Key rollover + * If you plan to update the SP x509cert and privateKey + * you can define here the new x509cert and it will be + * published on the SP metadata so Identity Providers can + * read them and get ready for rollover. + */ + // 'x509certNew' => '', + ), + + // Identity Provider Data that we want connected with our SP. + 'idp' => array ( + // Identifier of the IdP entity (must be a URI) + 'entityId' => '', + // SSO endpoint info of the IdP. (Authentication Request protocol) + 'singleSignOnService' => array ( + // URL Target of the IdP where the Authentication Request Message + // will be sent. + 'url' => '', + // SAML protocol binding to be used when returning the + // message. SAML Toolkit supports the HTTP-Redirect binding + // only for this endpoint. + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + ), + // SLO endpoint info of the IdP. + 'singleLogoutService' => array ( + // URL Location of the IdP where SLO Request will be sent. + 'url' => '', + // URL location of the IdP where the SP will send the SLO Response (ResponseLocation) + // if not set, url for the SLO Request will be used + 'responseUrl' => '', + // SAML protocol binding to be used when returning the + // message. SAML Toolkit supports the HTTP-Redirect binding + // only for this endpoint. + 'binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect', + ), + // Public x509 certificate of the IdP + 'x509cert' => '', + /* + * Instead of use the whole x509cert you can use a fingerprint in order to + * validate a SAMLResponse, but we don't recommend to use that + * method on production since is exploitable by a collision attack. + * (openssl x509 -noout -fingerprint -in "idp.crt" to generate it, + * or add for example the -sha256 , -sha384 or -sha512 parameter) + * + * If a fingerprint is provided, then the certFingerprintAlgorithm is required in order to + * let the toolkit know which algorithm was used. Possible values: sha1, sha256, sha384 or sha512 + * 'sha1' is the default value. + * + * Notice that if you want to validate any SAML Message sent by the HTTP-Redirect binding, you + * will need to provide the whole x509cert. + */ + // 'certFingerprint' => '', + // 'certFingerprintAlgorithm' => 'sha1', + + /* In some scenarios the IdP uses different certificates for + * signing/encryption, or is under key rollover phase and + * more than one certificate is published on IdP metadata. + * In order to handle that the toolkit offers that parameter. + * (when used, 'x509cert' and 'certFingerprint' values are + * ignored). + */ + // 'x509certMulti' => array( + // 'signing' => array( + // 0 => '', + // ), + // 'encryption' => array( + // 0 => '', + // ) + // ), + ), +); +``` +In addition to the required settings data (IdP, SP), there is extra +information that could be defined. In the same way that a template exists +for the basic info, there is a template for that advanced info located +at the base folder of the toolkit and named `advanced_settings_example.php` +that you can copy and rename it as `advanced_settings.php` + +```php + array ( + 'requests' => true, + 'responses' => true + ), + // Security settings + 'security' => array ( + + /** signatures and encryptions offered */ + + // Indicates that the nameID of the sent by this SP + // will be encrypted. + 'nameIdEncrypted' => false, + + // Indicates whether the messages sent by this SP + // will be signed. [Metadata of the SP will offer this info] + 'authnRequestsSigned' => false, + + // Indicates whether the messages sent by this SP + // will be signed. + 'logoutRequestSigned' => false, + + // Indicates whether the messages sent by this SP + // will be signed. + 'logoutResponseSigned' => false, + + /* Sign the Metadata + False || True (use sp certs) || array ( + keyFileName => 'metadata.key', + certFileName => 'metadata.crt' + ) + || array ( + 'x509cert' => '', + 'privateKey' => '' + ) + */ + 'signMetadata' => false, + + /** signatures and encryptions required **/ + + // Indicates a requirement for the , + // and elements received by this SP to be signed. + 'wantMessagesSigned' => false, + + // Indicates a requirement for the elements received by + // this SP to be encrypted. + 'wantAssertionsEncrypted' => false, + + // Indicates a requirement for the elements received by + // this SP to be signed. [Metadata of the SP will offer this info] + 'wantAssertionsSigned' => false, + + // Indicates a requirement for the NameID element on the SAMLResponse + // received by this SP to be present. + 'wantNameId' => true, + + // Indicates a requirement for the NameID received by + // this SP to be encrypted. + 'wantNameIdEncrypted' => false, + + // Authentication context. + // Set to false and no AuthContext will be sent in the AuthNRequest. + // Set true or don't present this parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport'. + // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'). + 'requestedAuthnContext' => false, + + // Indicates if the SP will validate all received xmls. + // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true). + 'wantXMLValidation' => true, + + // If true, SAMLResponses with an empty value at its Destination + // attribute will not be rejected for this fact. + 'relaxDestinationValidation' => false, + + // If true, the toolkit will not raised an error when the Statement Element + // contain atribute elements with name duplicated + 'allowRepeatAttributeName' => false, + + // If true, Destination URL should strictly match to the address to + // which the response has been sent. + // Notice that if 'relaxDestinationValidation' is true an empty Destination + // will be accepted. + 'destinationStrictlyMatches' => false, + + // If true, SAMLResponses with an InResponseTo value will be rejected if not + // AuthNRequest ID provided to the validation method. + 'rejectUnsolicitedResponsesWithInResponseTo' => false, + + // Algorithm that the toolkit will use on signing process. Options: + // 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' + // 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' + // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' + // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384' + // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512' + // Notice that sha1 is a deprecated algorithm and should not be used + 'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + + // Algorithm that the toolkit will use on digest process. Options: + // 'http://www.w3.org/2000/09/xmldsig#sha1' + // 'http://www.w3.org/2001/04/xmlenc#sha256' + // 'http://www.w3.org/2001/04/xmldsig-more#sha384' + // 'http://www.w3.org/2001/04/xmlenc#sha512' + // Notice that sha1 is a deprecated algorithm and should not be used + 'digestAlgorithm' => 'http://www.w3.org/2001/04/xmlenc#sha256', + + // ADFS URL-Encodes SAML data as lowercase, and the toolkit by default uses + // uppercase. Turn it True for ADFS compatibility on signature verification + 'lowercaseUrlencoding' => false, + ), + + // Contact information template, it is recommended to supply a + // technical and support contacts. + 'contactPerson' => array ( + 'technical' => array ( + 'givenName' => '', + 'emailAddress' => '' + ), + 'support' => array ( + 'givenName' => '', + 'emailAddress' => '' + ), + ), + + // Organization information template, the info in en_US lang is + // recommended, add more if required. + 'organization' => array ( + 'en-US' => array( + 'name' => '', + 'displayname' => '', + 'url' => '' + ), + ), +); +``` + +The compression settings allow you to instruct whether or not the IdP can accept +data that has been compressed using [gzip](gzip) ('requests' and 'responses'). +But if we provide a `$deflate` boolean parameter to the `getRequest` or `getResponse` method it will have priority over the compression settings. + +In the security section, you can set the way that the SP will handle the messages +and assertions. Contact the admin of the IdP and ask him what the IdP expects, +and decide what validations will handle the SP and what requirements the SP will have +and communicate them to the IdP's admin too. + +Once we know what kind of data could be configured, let's talk about the way +settings are handled within the toolkit. + +The settings files described (`settings.php` and `advanced_settings.php`) are loaded +by the toolkit if no other array with settings info is provided in the constructor of the toolkit. Let's see some examples. + +```php +// Initializes toolkit with settings.php & advanced_settings files. +$auth = new OneLogin_Saml2_Auth(); +//or +$settings = new OneLogin_Saml2_Settings(); + +// Initializes toolkit with the array provided. +$auth = new OneLogin_Saml2_Auth($settingsInfo); +//or +$settings = new OneLogin_Saml2_Settings($settingsInfo); +``` + +You can declare the `$settingsInfo` in the file that contains the constructor +execution or locate them in any file and load the file in order to get the +array available as we see in the following example: + +```php +login(); // Method that sent the AuthNRequest +``` + +The `AuthNRequest` will be sent signed or unsigned based on the security info +of the `advanced_settings.php` (`'authnRequestsSigned'`). + + +The IdP will then return the SAML Response to the user's client. The client is then forwarded to the Attribute Consumer Service of the SP with this information. If we do not set a `'url'` param in the login method and we are using the default ACS provided by the toolkit (`endpoints/acs.php`), then the ACS endpoint will redirect the user to the file that launched the SSO request. + +We can set a `'returnTo'` url to change the workflow and redirect the user to the other PHP file. + +```php +$newTargetUrl = 'http://example.com/consume2.php'; +$auth = new OneLogin_Saml2_Auth(); +$auth->login($newTargetUrl); +``` + +The login method can receive other six optional parameters: + +* `$parameters` - An array of parameters that will be added to the `GET` in the HTTP-Redirect. +* `$forceAuthn` - When true the `AuthNRequest` will set the `ForceAuthn='true'` +* `$isPassive` - When true the `AuthNRequest` will set the `Ispassive='true'` +* `$stay` - True if we want to stay (returns the url string) False to redirect +* `$setNameIdPolicy` - When true the AuthNRequest will set a nameIdPolicy element. +* `$nameIdValueReq` - Indicates to the IdP the subject that should be authenticated. + +If a match on the future SAMLResponse ID and the AuthNRequest ID to be sent is required, that AuthNRequest ID must to be extracted and saved. + +```php +$ssoBuiltUrl = $auth->login(null, array(), false, false, true); +$_SESSION['AuthNRequestID'] = $auth->getLastRequestID(); +header('Pragma: no-cache'); +header('Cache-Control: no-cache, must-revalidate'); +header('Location: ' . $ssoBuiltUrl); +exit(); +``` + +#### The SP Endpoints #### + +Related to the SP there are three important views: The metadata view, the ACS view and the SLS view. The toolkit +provides examples of those views in the endpoints directory. + +##### SP Metadata `endpoints/metadata.php` ##### + +This code will provide the XML metadata file of our SP, based on the info that we provided in the settings files. + +```php +getSettings(); + $metadata = $settings->getSPMetadata(); + $errors = $settings->validateMetadata($metadata); + if (empty($errors)) { + header('Content-Type: text/xml'); + echo $metadata; + } else { + throw new OneLogin_Saml2_Error( + 'Invalid SP metadata: '.implode(', ', $errors), + OneLogin_Saml2_Error::METADATA_SP_INVALID + ); + } +} catch (Exception $e) { + echo $e->getMessage(); +} +``` +The `getSPMetadata` will return the metadata signed or not based +on the security info of the `advanced_settings.php` (`'signMetadata'`). + +Before the XML metadata is exposed, a check takes place to ensure +that the info to be provided is valid. + +Instead of use the Auth object, you can directly use + +```php +$settings = new OneLogin_Saml2_Settings($settingsInfo, true); +``` +to get the settings object and with the true parameter we will avoid the IdP Settings validation. + + +##### Attribute Consumer Service(ACS) `endpoints/acs.php` ##### + +This code handles the SAML response that the IdP forwards to the SP through the user's client. + +```php +processResponse($requestID); +unset($_SESSION['AuthNRequestID']); + +$errors = $auth->getErrors(); + +if (!empty($errors)) { + echo '

', implode(', ', $errors), '

'; + exit(); +} + +if (!$auth->isAuthenticated()) { + echo "

Not authenticated

"; + exit(); +} + +$_SESSION['samlUserdata'] = $auth->getAttributes(); +$_SESSION['samlNameId'] = $auth->getNameId(); +$_SESSION['samlNameIdFormat'] = $auth->getNameIdFormat(); +$_SESSION['samlNameidNameQualifier'] = $auth->getNameIdNameQualifier(); +$_SESSION['samlNameidSPNameQualifier'] = $auth->getNameIdSPNameQualifier(); +$_SESSION['samlSessionIndex'] = $auth->getSessionIndex(); + +if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) { + // To avoid 'Open Redirect' attacks, before execute the + // redirection confirm the value of $_POST['RelayState'] is a // trusted URL. + $auth->redirectTo($_POST['RelayState']); +} + +$attributes = $_SESSION['samlUserdata']; +$nameId = $_SESSION['samlNameId']; + +echo '

Identified user: '. htmlentities($nameId) .'

'; + +if (!empty($attributes)) { + echo '

'._('User attributes:').'

'; + echo ''; + foreach ($attributes as $attributeName => $attributeValues) { + echo ''; + } + echo '
'._('Name').''._('Values').'
' . htmlentities($attributeName) . '
    '; + foreach ($attributeValues as $attributeValue) { + echo '
  • ' . htmlentities($attributeValue) . '
  • '; + } + echo '
'; +} else { + echo _('No attributes found.'); +} +``` + +The SAML response is processed and then checked that there are no errors. +It also verifies that the user is authenticated and stored the userdata in session. + +At that point there are two possible alternatives: + + 1. If no `RelayState` is provided, we could show the user data in this view + or however we wanted. + + 2. If `RelayState` is provided, a redirection takes place. + +Notice that we saved the user data in the session before the redirection to +have the user data available at the `RelayState` view. + + +###### The `getAttributes` method ###### + +In order to retrieve attributes we can use: + +```php +$attributes = $auth->getAttributes(); +``` + +With this method we get all the user data provided by the IdP in the Assertion +of the SAML Response. + +If we execute ```print_r($attributes)``` we could get: + +```php +Array +( + [cn] => Array + ( + [0] => John + ) + [sn] => Array + ( + [0] => Doe + ) + [mail] => Array + ( + [0] => john.doe@example.com + ) + [groups] => Array + ( + [0] => users + [1] => members + ) +) +``` + +Each attribute name can be used as an index into `$attributes` to obtain the value. Every attribute value +is an array - a single-valued attribute is an array of a single element. + + +The following code is equivalent: + +```php +$attributes = $auth->getAttributes(); +print_r($attributes['cn']); +``` + +```php +print_r($auth->getAttribute('cn')); +``` + + +Before trying to get an attribute, check that the user is +authenticated. If the user isn't authenticated or if there were +no attributes in the SAML assertion, an empty array will be +returned. For example, if we call to `getAttributes` before a +`$auth->processResponse`, the `getAttributes()` will return an +empty array. + + +##### Single Logout Service (SLS) `endpoints/sls.php` ##### + +This code handles the Logout Request and the Logout Responses. + +```php +processSLO(false, $requestID); + +$errors = $auth->getErrors(); + +if (empty($errors)) { + echo 'Successfully logged out'; +} else { + echo implode(', ', $errors); +} +``` + +If the SLS endpoints receives a Logout Response, the response is +validated and the session could be closed + + + +```php +// part of the processSLO method + +$logoutResponse = new OneLogin_Saml2_LogoutResponse($this->_settings, $_GET['SAMLResponse']); +if (!$logoutResponse->isValid($requestId)) { + $this->_errors[] = 'invalid_logout_response'; +} else if ($logoutResponse->getStatus() !== OneLogin_Saml2_Constants::STATUS_SUCCESS) { + $this->_errors[] = 'logout_not_success'; +} else { + if (!$keepLocalSession) { + OneLogin_Saml2_Utils::deleteLocalSession(); + } +} +``` + +If the SLS endpoints receives an Logout Request, the request is validated, +the session is closed and a Logout Response is sent to the SLS endpoint of +the IdP. + +```php +// part of the processSLO method + +$decoded = base64_decode($_GET['SAMLRequest']); +$request = gzinflate($decoded); +if (!OneLogin_Saml2_LogoutRequest::isValid($this->_settings, $request)) { + $this->_errors[] = 'invalid_logout_request'; +} else { + if (!$keepLocalSession) { + OneLogin_Saml2_Utils::deleteLocalSession(); + } + + $inResponseTo = $request->id; + $responseBuilder = new OneLogin_Saml2_LogoutResponse($this->_settings); + $responseBuilder->build($inResponseTo); + $logoutResponse = $responseBuilder->getResponse(); + + $parameters = array('SAMLResponse' => $logoutResponse); + if (isset($_GET['RelayState'])) { + $parameters['RelayState'] = $_GET['RelayState']; + } + + $security = $this->_settings->getSecurityData(); + if (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned']) { + $signature = $this->buildResponseSignature($logoutResponse, $parameters['RelayState'], $security['signatureAlgorithm']); + $parameters['SigAlg'] = $security['signatureAlgorithm']; + $parameters['Signature'] = $signature; + } + + $this->redirectTo($this->getSLOurl(), $parameters); +} +``` + +If you aren't using the default PHP session, or otherwise need a manual +way to destroy the session, you can pass a callback method to the +`processSLO` method as the fourth parameter + +```php +$keepLocalSession = False; +$callback = function () { + // Destroy user session +}; + +$auth->processSLO($keepLocalSession, null, false, $callback); +``` + + +If we don't want that `processSLO` to destroy the session, pass a true +parameter to the `processSLO` method + +```php +$keepLocalSession = True; +$auth->processSLO($keepLocalSession); +``` + +#### Initiate SLO #### + +In order to send a Logout Request to the IdP: + +```php +logout(); // Method that sent the Logout Request. +``` + +Also there are eight optional parameters that can be set: +* `$returnTo` - The target URL the user should be returned to after logout. +* `$parameters` - Extra parameters to be added to the GET. +* `$name_id` - That will be used to build the LogoutRequest. If `name_id` parameter is not set and the auth object processed a +SAML Response with a `NameId`, then this `NameId` will be used. +* `$session_index` - SessionIndex that identifies the session of the user. +* `$stay` - True if we want to stay (returns the url string) False to redirect. +* `$nameIdFormat` - The NameID Format will be set in the LogoutRequest. +* `$nameIdNameQualifier` - The NameID NameQualifier will be set in the LogoutRequest. +* `$nameIdSPNameQualifier` - The NameID SP NameQualifier will be set in the LogoutRequest. + +The Logout Request will be sent signed or unsigned based on the security +info of the `advanced_settings.php` (`'logoutRequestSigned'`). + +The IdP will return the Logout Response through the user's client to the +Single Logout Service of the SP. +If we do not set a `'url'` param in the logout method and are using the +default SLS provided by the toolkit (`endpoints/sls.php`), then the SLS +endpoint will redirect the user to the file that launched the SLO request. + +We can set an `'returnTo'` url to change the workflow and redirect the user +to other php file. + +```php +$newTargetUrl = 'http://example.com/loggedOut.php'; +$auth = new OneLogin_Saml2_Auth(); +$auth->logout($newTargetUrl); +``` +A more complex logout with all the parameters: +``` +$auth = new OneLogin_Saml2_Auth(); +$returnTo = null; +$paramters = array(); +$nameId = null; +$sessionIndex = null; +$nameIdFormat = null; +$nameIdNameQualifier = null; +$nameIdSPNameQualifier = null; + +if (isset($_SESSION['samlNameId'])) { + $nameId = $_SESSION['samlNameId']; +} +if (isset($_SESSION['samlSessionIndex'])) { + $sessionIndex = $_SESSION['samlSessionIndex']; +} +if (isset($_SESSION['samlNameIdFormat'])) { + $nameIdFormat = $_SESSION['samlNameIdFormat']; +} +if (isset($_SESSION['samlNameIdNameQualifier'])) { + $nameIdNameQualifier = $_SESSION['samlNameIdNameQualifier']; +} +if (isset($_SESSION['samlNameIdSPNameQualifier'])) { + $nameIdSPNameQualifier = $_SESSION['samlNameIdSPNameQualifier']; +} +$auth->logout($returnTo, $paramters, $nameId, $sessionIndex, false, $nameIdFormat, $nameIdNameQualifier, $nameIdSPNameQualifier); +``` + +If a match on the future LogoutResponse ID and the LogoutRequest ID to be sent is required, that LogoutRequest ID must to be extracted and stored. + +```php +$sloBuiltUrl = $auth->logout(null, $paramters, $nameId, $sessionIndex, true); +$_SESSION['LogoutRequestID'] = $auth->getLastRequestID(); +header('Pragma: no-cache'); +header('Cache-Control: no-cache, must-revalidate'); +header('Location: ' . $sloBuiltUrl); +exit(); +``` + +#### Example of a view that initiates the SSO request and handles the response (is the acs target) #### + +We can code a unique file that initiates the SSO process, handle the response, get the attributes, initiate +the SLO and processes the logout response. + +Note: Review the `demo1` folder that contains that use case; in a later section we +explain the demo1 use case further in detail. + +```php +login(); +} else if (isset($_GET['sso2'])) { // Another SSO action + $returnTo = $spBaseUrl.'/demo1/attrs.php'; // but set a custom RelayState URL + $auth->login($returnTo); +} else if (isset($_GET['slo'])) { // SLO action. Will sent a Logout Request to IdP + $auth->logout(); +} else if (isset($_GET['acs'])) { // Assertion Consumer Service + $auth->processResponse(); // Process the Response of the IdP, get the + // attributes and put then at + // $_SESSION['samlUserdata'] + + $errors = $auth->getErrors(); // This method receives an array with the errors + // that could took place during the process + + if (!empty($errors)) { + echo '

', implode(', ', $errors), '

'; + } + // This check if the response was + if (!$auth->isAuthenticated()) { // successfully validated and the user + echo "

Not authenticated

"; // data retrieved or not + exit(); + } + + $_SESSION['samlUserdata'] = $auth->getAttributes(); // Retrieves user data + if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) { + // To avoid 'Open Redirect' attacks, before execute the + // redirection confirm the value of $_POST['RelayState'] is a // trusted URL. + $auth->redirectTo($_POST['RelayState']); // Redirect if there is a + } // relayState set +} else if (isset($_GET['sls'])) { // Single Logout Service + $auth->processSLO(); // Process the Logout Request & Logout Response + $errors = $auth->getErrors(); // Retrieves possible validation errors + if (empty($errors)) { + echo '

Successfully logged out

'; + } else { + echo '

', implode(', ', $errors), '

'; + } +} + +if (isset($_SESSION['samlUserdata'])) { // If there is user data we print it. + if (!empty($_SESSION['samlUserdata'])) { + $attributes = $_SESSION['samlUserdata']; + echo 'You have the following attributes:
'; + echo ''; + foreach ($attributes as $attributeName => $attributeValues) { + echo ''; + } + echo '
NameValues
' . htmlentities($attributeName) . '
    '; + foreach ($attributeValues as $attributeValue) { + echo '
  • ' . htmlentities($attributeValue) . '
  • '; + } + echo '
'; + } else { // If there is not user data, we notify + echo "

You don't have any attribute

"; + } + + echo '

Logout

'; // Print some links with possible +} else { // actions + echo '

Login

'; + echo '

Login and access to attrs.php page

'; +} +``` + +#### Example (using Composer) that initiates the SSO request and handles the response (is the acs target) #### + +Install package via composer: +``` +composer require onelogin/php-saml +``` + +Create an index.php: +```php +processResponse(null); + $errors = $auth->getErrors(); + if (empty($errors)) { + // user has authenticated successfully + $needsAuth = false; + $_SESSION['samlUserdata'] = $auth->getAttributes(); + } + } + + if ($needsAuth) { + $auth->login(); + } +} + +// rest of your app goes here +``` + +#### URL-guessing methods #### + +php-saml toolkit uses a bunch of methods in OneLogin_Saml2_Utils that try to guess the URL where the SAML messages are processed. + +* `getSelfHost` Returns the current host. +* `getSelfPort` Return the port number used for the request +* `isHTTPS` Checks if the protocol is https or http. +* `getSelfURLhost` Returns the protocol + the current host + the port (if different than common ports). +* `getSelfURL` Returns the URL of the current host + current view + query. +* `getSelfURLNoQuery` Returns the URL of the current host + current view. +* `getSelfRoutedURLNoQuery` Returns the routed URL of the current host + current view. + +getSelfURLNoQuery and getSelfRoutedURLNoQuery are used to calculate the currentURL in order to validate SAML elements like Destination or Recipient. + +When the PHP application is behind a proxy or a load balancer we can execute `setProxyVars(true)` and `setSelfPort` and `isHTTPS` will take care of the `$_SERVER["HTTP_X_FORWARDED_PORT"]` and `$_SERVER['HTTP_X_FORWARDED_PROTO']` vars (otherwise they are ignored). + +Also a developer can use `setSelfProtocol`, `setSelfHost`, `setSelfPort` and `getBaseURLPath` to define a specific value to be returned by `isHTTPS`, `getSelfHost`, `getSelfPort` and `getBaseURLPath`. And define a `setBasePath` to be used on the `getSelfURL` and `getSelfRoutedURLNoQuery` to replace the data extracted from `$_SERVER["REQUEST_URI"]`. + +At the settings the developer will be able to set a `'baseurl'` parameter that automatically will use `setBaseURL` to set values for `setSelfProtocol`, `setSelfHost`, `setSelfPort` and `setBaseURLPath`. + + +### Working behind load balancer ### + +Is possible that asserting request URL and Destination attribute of SAML response fails when working behind load balancer with SSL offload. + +You should be able to workaround this by configuring your server so that it is aware of the proxy and returns the original url when requested. + +Or by using the method described on the previous section. + + +### SP Key rollover ### + +If you plan to update the SP x509cert and privateKey you can define the new x509cert as `$settings['sp']['x509certNew']` and it will be +published on the SP metadata so Identity Providers can read them and get ready for rollover. + + +### IdP with multiple certificates ### + +In some scenarios the IdP uses different certificates for +signing/encryption, or is under key rollover phase and more than one certificate is published on IdP metadata. + +In order to handle that the toolkit offers the `$settings['idp']['x509certMulti']` parameter. + +When that parameter is used, `'x509cert'` and `'certFingerprint'` values will be ignored by the toolkit. + +The `'x509certMulti'` is an array with 2 keys: +- `'signing'`. An array of certs that will be used to validate IdP signature +- `'encryption'` An array with one unique cert that will be used to encrypt data to be sent to the IdP + + +### Replay attacks ### + +In order to avoid replay attacks, you can store the ID of the SAML messages already processed, to avoid processing them twice. Since the Messages expires and will be invalidated due that fact, you don't need to store those IDs longer than the time frame that you currently accepting. + +Get the ID of the last processed message/assertion with the `getLastMessageId/getLastAssertionId` methods of the Auth object. + + +### Main classes and methods ### + +Described below are the main classes and methods that can be invoked. + +#### The Old Saml library #### + +Lets start describing the classes and methods of the SAML library, an evolution +of the old v.1 toolkit that is provided to keep the backward compability. +Most of them use classes and methods of the new SAML2 library. + +##### OneLogin_Saml_AuthRequest - `AuthRequest.php` ##### + +Has the protected attribute `$auth`, an `OneLogin_Saml2_Auth` object. + +* `OneLogin_Saml_AuthRequest` - Constructs `OneLogin_Saml2_Auth`, + initializing the SP SAML instance. +* `getRedirectUrl($returnTo)` - Obtains the SSO URL containing the AuthRequest + message deflated. + + +##### OneLogin_Saml_Response - `Response.php` ##### + +* `OneLogin_Saml_Response` - Constructor that process the SAML Response, + Internally initializes an SP SAML instance and an `OneLogin_Saml2_Response`. +* `get_saml_attributes` - Retrieves an Array with the logged user data. + + +##### OneLogin_Saml_Settings - `Settings.php` ##### + +A simple class used to build the Setting object used in the v1.0 of the toolkit. + +##### OneLogin_Saml_Metadata - `Metadata.php` ##### + +* `OneLogin_Saml_Metadata` - Constructor that build the Metadata XML info based + on the settings of the SP +* `getXml` - An XML with the metadata info of the SP + + +##### OneLogin_Saml_XmlSec - `XmlSec.php` ##### + +Auxiliary class that contains methods to validate the SAML Response: +`validateNumAssertions`, `validateTimestamps`, `isValid` (which +uses the other two previous methods and also validate the signature of +SAML Response). + + +#### Saml2 library #### + +Lets describe now the classes and methods of the SAML2 library. + +##### OneLogin_Saml2_Auth - Auth.php ##### + +Main class of PHP Toolkit + + * `OneLogin_Saml2_Auth` - Initializes the SP SAML instance + * `login` - Initiates the SSO process. + * `logout` - Initiates the SLO process. + * `processResponse` - Process the SAML Response sent by the IdP. + * `processSLO` - Process the SAML Logout Response / Logout Request sent by the + IdP. + * `redirectTo` - Redirects the user to the url past by parameter or to the url + that we defined in our SSO Request. + * `isAuthenticated` - Checks if the user is authenticated or not. + * `getAttributes` - Returns the set of SAML attributes. + * `getAttribute` - Returns the requested SAML attribute + * `getNameId` - Returns the nameID + * `getNameIdFormat` - Gets the NameID Format provided by the SAML response from the IdP. + * `getNameIdNameQualifier` - Gets the NameID NameQualifier provided from the SAML Response String. + * `getNameIdSPNameQualifier` - Gets the NameID SP NameQualifier provided from the SAML Response String. + * `getSessionIndex` - Gets the SessionIndex from the AuthnStatement. + * `getErrors` - Returns if there were any error + * `getSSOurl` - Gets the SSO url. + * `getSLOurl` - Gets the SLO url. + * `getLastRequestID` - The ID of the last Request SAML message generated. + * `buildRequestSignature` - Generates the Signature for a SAML Request + * `buildResponseSignature` - Generates the Signature for a SAML Response + * `getSettings` - Returns the settings info + * `setStrict` - Set the strict mode active/disable + * `getLastRequestID` - Gets the ID of the last AuthNRequest or LogoutRequest generated by the Service Provider. + * `getLastRequestXML` - Returns the most recently-constructed/processed XML SAML request (AuthNRequest, LogoutRequest) + * `getLastResponseXML` - Returns the most recently-constructed/processed XML SAML response (SAMLResponse, LogoutResponse). If the SAMLResponse had an encrypted assertion, decrypts it. + + +##### OneLogin_Saml2_AuthnRequest - `AuthnRequest.php` ##### + +SAML 2 Authentication Request class + + * `OneLogin_Saml2_AuthnRequest` - Constructs the `AuthnRequest` object. + * `getRequest` - Returns deflated, base64 encoded, unsigned `AuthnRequest`. + * `getId` - Returns the `AuthNRequest` ID. + * `getXML` - Returns the XML that will be sent as part of the request. + +##### OneLogin_Saml2_Response - `Response.php` ##### + +SAML 2 Authentication Response class + + * `OneLogin_Saml2_Response` - Constructs the SAML Response object. + * `isValid` - Determines if the SAML Response is valid using the certificate. + * `checkStatus` - Checks if the Status is success. + * `getAudiences` - Gets the audiences. + * `getIssuers` - Gets the Issuers (from Response and Assertion) + * `getNameIdData` - Gets the NameID Data provided by the SAML response from the + IdP. + * `getNameId` - Gets the NameID provided by the SAML response from the IdP. + * `getNameIdFormat` - Gets the NameID Format provided by the SAML response from the IdP. + * `getNameIdNameQualifier` - Gets the NameID NameQualifier provided from the SAML Response String. + * `getNameIdSPNameQualifier` - Gets the NameID SP NameQualifier provided from the SAML Response String. + * `getSessionNotOnOrAfter` - Gets the SessionNotOnOrAfter from the + AuthnStatement + * `getSessionIndex` - Gets the SessionIndex from the AuthnStatement. + * `getAttributes` - Gets the Attributes from the AttributeStatement element. + * `validateNumAssertions` - Verifies that the document only contains a single + Assertion (encrypted or not). + * `validateTimestamps` - Verifies that the document is still valid according + Conditions Element. + * `getError` - After executing a validation process, if it fails, this method returns the cause + * `getXMLDocument` - Returns the SAML Response document (If contains an encrypted assertion, decrypts it) + +##### OneLogin_Saml2_LogoutRequest - `LogoutRequest.php` ##### + +SAML 2 Logout Request class + + * `OneLogin_Saml2_LogoutRequest` - Constructs the Logout Request object. + * `getRequest` - Returns the Logout Request deflated, base64encoded, unsigned + * `getID` - Returns the ID of the Logout Request. (If you have the object you can access to the id attribute) + * `getNameIdData` - Gets the NameID Data of the the Logout Request. + * `getNameId` - Gets the NameID of the Logout Request. + * `getIssuer` - Gets the Issuer of the Logout Request. + * `getSessionIndexes` - Gets the SessionIndexes from the Logout Request. + * `isValid` - Checks if the Logout Request received is valid. + * `getError` - After executing a validation process, if it fails, this method returns the cause + * `getXML` - Returns the XML that will be sent as part of the request or that was received at the SP. + +##### OneLogin_Saml2_LogoutResponse - `LogoutResponse.php` ##### + +SAML 2 Logout Response class + + * `OneLogin_Saml2_LogoutResponse` - Constructs a Logout Response object + (Initialize params from settings and if provided load the Logout Response) + * `getIssuer` - Gets the Issuer of the Logout Response. + * `getStatus` - Gets the Status of the Logout Response. + * `isValid` - Determines if the SAML LogoutResponse is valid + * `build` - Generates a Logout Response object. + * `getResponse` - Returns a Logout Response object. + * `getError` - After executing a validation process, if it fails, this method returns the cause. + * `getXML` - Returns the XML that will be sent as part of the response or that was received at the SP. + +##### OneLogin_Saml2_Settings - `Settings.php` ##### + +Configuration of the PHP Toolkit + + * `OneLogin_Saml2_Settings` - Initializes the settings: Sets the paths of + the different folders and Loads settings info from settings file or + array/object provided + * `checkSettings` - Checks the settings info. + * `getBasePath` - Returns base path. + * `getCertPath` - Returns cert path. + * `getLibPath` - Returns lib path. + * `getExtLibPath` - Returns external lib path. + * `getSchemasPath` - Returns schema path. + * `checkSPCerts` - Checks if the x509 certs of the SP exists and are valid. + * `getSPkey` - Returns the x509 private key of the SP. + * `getSPcert` - Returns the x509 public cert of the SP. + * `getSPcertNew` - Returns the future x509 public cert of the SP. + * `getIdPData` - Gets the IdP data. + * `getSPData`Gets the SP data. + * `getSecurityData` - Gets security data. + * `getContacts` - Gets contact data. + * `getOrganization` - Gets organization data. + * `getSPMetadata` - Gets the SP metadata. The XML representation. + * `validateMetadata` - Validates an XML SP Metadata. + * `formatIdPCert` - Formats the IdP cert. + * `formatSPCert` - Formats the SP cert. + * `formatSPCertNew` - Formats the SP cert new. + * `formatSPKey` - Formats the SP private key. + * `getErrors` - Returns an array with the errors, the array is empty when + the settings is ok. + * `getLastErrorReason` - Returns the reason of the last error + * `getBaseURL` - Returns the baseurl set on the settings if any. + * `setBaseURL` - Set a baseurl value + * `setStrict` - Activates or deactivates the strict mode. + * `isStrict` - Returns if the 'strict' mode is active. + * `isDebugActive` - Returns if the debug is active. + +##### OneLogin_Saml2_Metadata - `Metadata.php` ##### + +A class that contains functionality related to the metadata of the SP + +* `builder` - Generates the metadata of the SP based on the settings. +* `signmetadata` - Signs the metadata with the key/cert provided +* `addX509KeyDescriptors` - Adds the x509 descriptors (sign/encryption) to + the metadata + +##### OneLogin_Saml2_Utils - `Utils.php` ##### + +Auxiliary class that contains several methods + + * `validateXML` - This function attempts to validate an XML string against + the specified schema. + * `formatCert` - Returns a x509 cert (adding header & footer if required). + * `formatPrivateKey` - returns a RSA private key (adding header & footer if required). + * `redirect` - Executes a redirection to the provided url (or return the + target url). + * `isHTTPS` - Checks if https or http. + * `getSelfHost` - Returns the current host. + * `getSelfURLhost` - Returns the protocol + the current host + the port + (if different than common ports). + * `getSelfURLNoQuery` - Returns the URL of the current host + current view. + * `getSelfURL` - Returns the URL of the current host + current view + query. + * `generateUniqueID` - Generates a unique string (used for example as ID + for assertions). + * `parseTime2SAML` - Converts a UNIX timestamp to SAML2 timestamp on the + form `yyyy-mm-ddThh:mm:ss(\.s+)?Z`. + * `parseSAML2Time` - Converts a SAML2 timestamp on the form + `yyyy-mm-ddThh:mm:ss(\.s+)?Z` to a UNIX timestamp. The sub-second part is + ignored. + * `parseDuration` - Interprets a ISO8601 duration value relative to a given + timestamp. + * `getExpireTime` - Compares two dates and returns the earliest. + * `query` - Extracts nodes from the DOMDocument. + * `isSessionStarted` - Checks if the session is started or not. + * `deleteLocalSession` - Deletes the local session. + * `calculateX509Fingerprint` - Calculates the fingerprint of a x509cert. + * `formatFingerPrint` - Formats a fingerprint. + * `generateNameId` - Generates a `nameID`. + * `getStatus` - Gets Status from a Response. + * `decryptElement` - Decrypts an encrypted element. + * `castKey` - Converts a `XMLSecurityKey` to the correct algorithm. + * `addSign` - Adds signature key and senders certificate to an element + (Message or Assertion). + * `validateSign` - Validates a signature (Message or Assertion). + +##### OneLogin_Saml2_IdPMetadataParser - `IdPMetadataParser.php` ##### + +Auxiliary class that contains several methods to retrieve and process IdP metadata + + * `parseRemoteXML` - Get IdP Metadata Info from URL. + * `parseFileXML` - Get IdP Metadata Info from File. + * `parseXML` - Get IdP Metadata Info from XML. + * `injectIntoSettings` - Inject metadata info into php-saml settings array. + +The class does not validate in any way the URL that is introduced on methods like parseRemoteXML in order to retrieve the remove XML. Usually is the same administrator that handles the Service Provider the ones that set the URL that should belong to a trusted third-party IdP. +But there are other scenarios, like a SAAS app where the administrator of the app delegates on other administrators. In such case, extra protection should be taken in order to validate such URL inputs and avoid attacks like SSRF. + +For more info, look at the source code; each method is documented and details +about what it does and how to use it are provided. Make sure to also check the doc folder where +HTML documentation about the classes and methods is provided for SAML and +SAML2. + + + + +Demos included in the toolkit +----------------------------- + +The toolkit includes three demo apps to teach how use the toolkit, take a look on it. + +Demos require that SP and IdP are well configured before test it. + +## Demo1 ## + +### SP setup ### + +The PHP Toolkit allows you to provide the settings info in two ways: + + * Use a `settings.php` file that we should locate at the base folder of the + toolkit. + * Use an array with the setting data. + +In this demo we provide the data in the second way, using a setting array named +`$settingsInfo`. This array users the `settings_example.php` included as a template +to create the `settings.php` settings and store it in the `demo1/` folder. +Configure the SP part and later review the metadata of the IdP and complete the IdP info. + +If you check the code of the index.php file you will see that the `settings.php` +file is loaded in order to get the `$settingsInfo` var to be used in order to initialize +the `Setting` class. + +Notice that in this demo, the `setting.php` file that could be defined at the base +folder of the toolkit is ignored and the libs are loaded using the +`_toolkit_loader.php` located at the base folder of the toolkit. + + +### IdP setup ### + +Once the SP is configured, the metadata of the SP is published at the +`metadata.php` file. Configure the IdP based on that information. + + +### How it works ### + + 1. First time you access to `index.php` view, you can select to login and return + to the same view or login and be redirected to the `attrs.php` view. + + 2. When you click: + + 2.1 in the first link, we access to (`index.php?sso`) an `AuthNRequest` + is sent to the IdP, we authenticate at the IdP and then a Response is sent + through the user's client to the SP, specifically the Assertion Consumer Service view: `index.php?acs`. + Notice that a `RelayState` parameter is set to the url that initiated the + process, the `index.php` view. + + 2.2 in the second link we access to (`attrs.php`) have the same process + described at 2.1 with the difference that as `RelayState` is set the `attrs.php`. + + 3. The SAML Response is processed in the ACS (`index.php?acs`), if the Response + is not valid, the process stops here and a message is shown. Otherwise we + are redirected to the RelayState view. a) `index.php` or b) `attrs.php`. + + 4. We are logged in the app and the user attributes are showed. + At this point, we can test the single log out functionality. + + 5. The single log out functionality could be tested by two ways. + + 5.1 SLO Initiated by SP. Click on the "logout" link at the SP, after that a + Logout Request is sent to the IdP, the session at the IdP is closed and + replies through the client to the SP with a Logout Response (sent to the + Single Logout Service endpoint). The SLS endpoint (`index.php?sls`) of the SP + process the Logout Response and if is valid, close the user session of the + local app. Notice that the SLO Workflow starts and ends at the SP. + + 5.2 SLO Initiated by IdP. In this case, the action takes place on the IdP + side, the logout process is initiated at the idP, sends a Logout + Request to the SP (SLS endpoint, `index.php?sls`). The SLS endpoint of the SP + process the Logout Request and if is valid, close the session of the user + at the local app and send a Logout Response to the IdP (to the SLS endpoint + of the IdP). The IdP receives the Logout Response, process it and close the + session at of the IdP. Notice that the SLO Workflow starts and ends at the IdP. + +Notice that all the SAML Requests and Responses are handled by a unique file, +the `index.php` file and how `GET` parameters are used to know the action that +must be done. + + +## Demo2 ## + +### SP setup ### + +The PHP Toolkit allows you to provide the settings info in two ways: + + * Use a `settings.php` file that we should locate at the base folder of the + toolkit. + * Use an array with the setting data. + +The first is the case of the demo2 app. The `setting.php` file and the +`setting_extended.php` file should be defined at the base folder of the toolkit. +Review the `setting_example.php` and the `advanced_settings_example.php` to +learn how to build them. + +In this case as Attribute Consume Service and Single Logout Service we are going to +use the files located in the endpoint folder (`acs.php` and `sls.php`). + + +### IdP setup ### + +Once the SP is configured, the metadata of the SP is published at the +`metadata.php` file. Based on that info, configure the IdP. + + +### How it works ### + +In demo1, we saw how all the SAML Request and Responses were handler at an +unique file, the `index.php` file. This demo1 uses high-level programming. + +In demo2, we have several views: `index.php`, `sso.php`, `slo.php`, `consume.php` +and `metadata.php`. As we said, we will use the endpoints that are defined +in the toolkit (`acs.php`, `sls.php` of the endpoints folder). This demo2 uses +low-level programming. + +Notice that the SSO action can be initiated at `index.php` or `sso.php`. + +The SAML workflow that take place is similar that the workflow defined in the +demo1, only changes the targets. + + 1. When you access `index.php` or `sso.php` for the first time, an `AuthNRequest` is + sent to the IdP automatically, (as `RelayState` is sent the origin url). + We authenticate at the IdP and then a `Response` is sent to the SP, to the + ACS endpoint, in this case `acs.php` of the endpoints folder. + + 2. The SAML Response is processed in the ACS, if the `Response` is not valid, + the process stops here and a message is shown. Otherwise we are redirected + to the `RelayState` view (`sso.php` or `index.php`). The `sso.php` detects if the + user is logged and redirects to `index.php`, so we will be in the + `index.php` at the end. + + 3. We are logged into the app and the user attributes (if any) are shown. + At this point, we can test the single log out functionality. + + 4. The single log out functionality could be tested by two ways. + + 4.1 SLO Initiated by SP. Click on the "logout" link at the SP, after that + we are redirected to the `slo.php` view and there a Logout Request is sent + to the IdP, the session at the IdP is closed and replies to the SP a + Logout Response (sent to the Single Logout Service endpoint). In this case + The SLS endpoint of the SP process the Logout Response and if is + valid, close the user session of the local app. Notice that the SLO + Workflow starts and ends at the SP. + + 4.2 SLO Initiated by IdP. In this case, the action takes place on the IdP + side, the logout process is initiated at the idP, sends a Logout + Request to the SP (SLS endpoint `sls.php` of the endpoint folder). + The SLS endpoint of the SP process the Logout Request and if is valid, + close the session of the user at the local app and sends a Logout Response + to the IdP (to the SLS endpoint of the IdP).The IdP receives the Logout + Response, process it and close the session at of the IdP. Notice that the + SLO Workflow starts and ends at the IdP. + + +## Demo Old ## + +### SP setup ### + +This demo uses the old style of the version 1 of the toolkit. +An object of the class `OneLogin_Saml_Settings` must be provided to the +constructor of the `AuthRequest`. + +You will find an `example_settings.php` file at the demo-old's folder that +could be used as a template for your `settings.php` file. + +In that template, SAML settings are divided into two parts, the application +specific (`const_assertion_consumer_service_url`, `const_issuer`, +`const_name_identifier_format`) and the user/account specific +`idp_sso_target_url`, `x509certificate`). You'll need to add your own code here +to identify the user or user origin (e.g. by `subdomain`, `ip_address` etc.). + + +### IdP setup ### + +Once the SP is configured, the metadata of the SP is published at the +`metadata.php` file. After that, configure the IdP based on that information. + + +### How it works ### + +At the `metadata.php` view is published the metadata of the SP. + +The `index.php` file acts as an initiater for the SAML conversation if it should +should be initiated by the application. This is called Service Provider +Initiated SAML. The service provider creates a SAML Authentication Request and +sends it to the identity provider (IdP). + +The `consume.php` is the ACS endpoint. Receives the SAML assertion. After Response +validation, the userdata and the nameID will be available, using `getNameId()` or +`getAttributes()` we obtain them. + +Since the version 1 of the php toolkit does not support SLO we don't show how +handle SLO in this demo-old. diff --git a/_toolkit_loader.php b/_toolkit_loader.php new file mode 100644 index 00000000..e1e0c378 --- /dev/null +++ b/_toolkit_loader.php @@ -0,0 +1,25 @@ + array ( + 'requests' => true, + 'responses' => true + ), + + // Security settings + 'security' => array ( + + /** signatures and encryptions offered */ + + // Indicates that the nameID of the sent by this SP + // will be encrypted. + 'nameIdEncrypted' => false, + + // Indicates whether the messages sent by this SP + // will be signed. [The Metadata of the SP will offer this info] + 'authnRequestsSigned' => false, + + // Indicates whether the messages sent by this SP + // will be signed. + 'logoutRequestSigned' => false, + + // Indicates whether the messages sent by this SP + // will be signed. + 'logoutResponseSigned' => false, + + /* Sign the Metadata + False || True (use sp certs) || array ( + keyFileName => 'metadata.key', + certFileName => 'metadata.crt' + ) + || array ( + 'x509cert' => '', + 'privateKey' => '' + ) + */ + 'signMetadata' => false, + + + /** signatures and encryptions required **/ + + // Indicates a requirement for the , and + // elements received by this SP to be signed. + 'wantMessagesSigned' => false, + + // Indicates a requirement for the elements received by + // this SP to be encrypted. + 'wantAssertionsEncrypted' => false, + + // Indicates a requirement for the elements received by + // this SP to be signed. [The Metadata of the SP will offer this info] + 'wantAssertionsSigned' => false, + + // Indicates a requirement for the NameID element on the SAMLResponse received + // by this SP to be present. + 'wantNameId' => true, + + // Indicates a requirement for the NameID received by + // this SP to be encrypted. + 'wantNameIdEncrypted' => false, + + // Authentication context. + // Set to false and no AuthContext will be sent in the AuthNRequest, + // Set true or don't present this parameter and you will get an AuthContext 'exact' 'urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport' + // Set an array with the possible auth context values: array ('urn:oasis:names:tc:SAML:2.0:ac:classes:Password', 'urn:oasis:names:tc:SAML:2.0:ac:classes:X509'), + 'requestedAuthnContext' => false, + + // Allows the authn comparison parameter to be set, defaults to 'exact' if + // the setting is not present. + 'requestedAuthnContextComparison' => 'exact', + + // Indicates if the SP will validate all received xmls. + // (In order to validate the xml, 'strict' and 'wantXMLValidation' must be true). + 'wantXMLValidation' => true, + + // If true, SAMLResponses with an empty value at its Destination + // attribute will not be rejected for this fact. + 'relaxDestinationValidation' => false, + + // If true, the toolkit will not raised an error when the Statement Element + // contain atribute elements with name duplicated + 'allowRepeatAttributeName' => false, + + // If true, Destination URL should strictly match to the address to + // which the response has been sent. + // Notice that if 'relaxDestinationValidation' is true an empty Destination + // will be accepted. + 'destinationStrictlyMatches' => false, + + // If true, SAMLResponses with an InResponseTo value will be rejected if not + // AuthNRequest ID provided to the validation method. + 'rejectUnsolicitedResponsesWithInResponseTo' => false, + + // Algorithm that the toolkit will use on signing process. Options: + // 'http://www.w3.org/2000/09/xmldsig#rsa-sha1' + // 'http://www.w3.org/2000/09/xmldsig#dsa-sha1' + // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256' + // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384' + // 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512' + // Notice that sha1 is a deprecated algorithm and should not be used + 'signatureAlgorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', + + // Algorithm that the toolkit will use on digest process. Options: + // 'http://www.w3.org/2000/09/xmldsig#sha1' + // 'http://www.w3.org/2001/04/xmlenc#sha256' + // 'http://www.w3.org/2001/04/xmldsig-more#sha384' + // 'http://www.w3.org/2001/04/xmlenc#sha512' + // Notice that sha1 is a deprecated algorithm and should not be used + 'digestAlgorithm' => 'http://www.w3.org/2001/04/xmlenc#sha256', + + // ADFS URL-Encodes SAML data as lowercase, and the toolkit by default uses + // uppercase. Turn it True for ADFS compatibility on signature verification + 'lowercaseUrlencoding' => false, + ), + + // Contact information template, it is recommended to supply a technical and support contacts + 'contactPerson' => array ( + 'technical' => array ( + 'givenName' => '', + 'emailAddress' => '' + ), + 'support' => array ( + 'givenName' => '', + 'emailAddress' => '' + ), + ), + + // Organization information template, the info in en_US lang is recommended, add more if required + 'organization' => array ( + 'en-US' => array( + 'name' => '', + 'displayname' => '', + 'url' => '' + ), + ), +); + + +/* Interoperable SAML 2.0 Web Browser SSO Profile [saml2int] http://saml2int.org/profile/current + + 'authnRequestsSigned' => false, // SP SHOULD NOT sign the , + // MUST NOT assume that the IdP validates the sign + 'wantAssertionsSigned' => true, + 'wantAssertionsEncrypted' => true, // MUST be enabled if SSL/HTTPs is disabled + 'wantNameIdEncrypted' => false, +*/ diff --git a/certs/README b/certs/README new file mode 100644 index 00000000..ceee1f3e --- /dev/null +++ b/certs/README @@ -0,0 +1,12 @@ +Take care of this folder that could contain private key. Be sure that this folder never is published. + +PHP Toolkit expects certs for the SP stored at: + + * sp.key Private Key + * sp.crt Public cert + * sp_new.crt Future Public cert + +Also you can use other cert to sign the metadata of the SP using the: + + * metadata.key + * metadata.crt diff --git a/compatibility.php b/compatibility.php new file mode 100644 index 00000000..02a8108c --- /dev/null +++ b/compatibility.php @@ -0,0 +1,12 @@ +=5.3.2 <7.2", + "ext-curl": "*", + "ext-openssl": "*", + "ext-dom": "*", + "ext-mcrypt": "*", + "ext-zlib": "*" + }, + "require-dev": { + "phpunit/phpunit": "^4.8", + "satooshi/php-coveralls": "1.0.1", + "sebastian/phpcpd": "*", + "phploc/phploc": "*", + "pdepend/pdepend" : "1.1.0", + "squizlabs/php_codesniffer": "2.9.0" + } +} diff --git a/demo-old/Readme.txt b/demo-old/Readme.txt new file mode 100644 index 00000000..32d0c28c --- /dev/null +++ b/demo-old/Readme.txt @@ -0,0 +1,43 @@ +The example requires that SP and IdP are well configured before test it. + +SP setup +-------- + +This demo uses the old style of the version 1 of the toolkit. +An object of the class OneLogin_Saml_Settings must be provided to the +constructor of the AuthRequest. + +You will find an example_settings.php file at the demo-old's folder that +could be used as a template for you settings.php file. + +In that template, SAML settings are divided into two parts, the application +specific (const_assertion_consumer_service_url, const_issuer, +const_name_identifier_format) and the user/account specific +idp_sso_target_url, x509certificate). You’ll need to add your own code here +to identify the user or user origin (e.g. by subdomain, ip_address etc.). + + +IdP setup +--------- + +Once the SP is configured, the metadata of the SP is published at the +metadata.php file. Based on that info, configure the IdP. + + +How it works +------------ + +At the metadata.php view is published the metadata of the SP. + +The index.php file acts as an initiater for the SAML conversation, if it should +should be initiated by the application. This is called Service Service Provider +Initiated SAML. The service provider creates a SAML Authentication Request and +sends it to the identity provider (IdP). + +The consume.php is the ACS endpoint. Receives the SAML assertion. After Response +validation, the userdata and the nameID will be available, using getNameId() or +getAttributes() we obtain them. + + +Since the version 1 of the php toolkit does not support SLO we don't show how +handle SLO in this demo-old. diff --git a/demo/consume.php b/demo-old/consume.php similarity index 76% rename from demo/consume.php rename to demo-old/consume.php index b2a93d49..8d993a48 100644 --- a/demo/consume.php +++ b/demo-old/consume.php @@ -7,9 +7,7 @@ * link where it will send a certified response via $_POST. */ -error_reporting(E_ALL); - -$settings = NULL; +$settings = null; require 'settings.php'; $samlResponse = new OneLogin_Saml_Response($settings, $_POST['SAMLResponse']); @@ -23,18 +21,17 @@ echo ''; foreach ($attributes as $attributeName => $attributeValues) { echo ''; } - echo '
NameValues
' . htmlentities($attributeName) . '
    '; - foreach ($attributeValues as $attributeValue) { - echo '
  • ' . htmlentities($attributeValue) . '
  • '; - } + foreach ($attributeValues as $attributeValue) { + echo '
  • ' . htmlentities($attributeValue) . '
  • '; + } echo '
'; + echo '

'; + echo "The v.1 of the PHP SAML Tookit does not support SLO."; } - } - else { + } else { echo 'Invalid SAML response.'; } -} -catch (Exception $e) { +} catch (Exception $e) { echo 'Invalid SAML response: ' . $e->getMessage(); } diff --git a/demo/index.php b/demo-old/index.php similarity index 91% rename from demo/index.php rename to demo-old/index.php index d163defb..2854de3d 100755 --- a/demo/index.php +++ b/demo-old/index.php @@ -10,10 +10,10 @@ error_reporting(E_ALL); -$settings = NULL; +$settings = null; require 'settings.php'; $authRequest = new OneLogin_Saml_AuthRequest($settings); $url = $authRequest->getRedirectUrl(); -header("Location: $url"); \ No newline at end of file +header("Location: $url"); diff --git a/demo/metadata.php b/demo-old/metadata.php similarity index 83% rename from demo/metadata.php rename to demo-old/metadata.php index 7ebd3eeb..10d532ec 100644 --- a/demo/metadata.php +++ b/demo-old/metadata.php @@ -6,12 +6,10 @@ * or expose it on a URL so your IdP can check it periodically. */ -error_reporting(E_ALL); - -$settings = NULL; +$settings = null; require 'settings.php'; header('Content-Type: text/xml'); $samlMetadata = new OneLogin_Saml_Metadata($settings); -echo $samlMetadata->getXml(); \ No newline at end of file +echo $samlMetadata->getXml(); diff --git a/demo-old/settings_example.php b/demo-old/settings_example.php new file mode 100644 index 00000000..f33ba94f --- /dev/null +++ b/demo-old/settings_example.php @@ -0,0 +1,54 @@ +idpSingleSignOnUrl = ''; +// Initiate the SLO process, This URL asks the IdP to SLO the user. +$settings->idpSingleLogOutUrl = ''; + +// The certificate for the users account in the IdP +$settings->idpPublicCertificate = ''; + +// The URL where to the SAML Response/SAML Assertion will be posted +$settings->spReturnUrl = ''; + +// Name of this application +$settings->spIssuer = ''; + +// Tells the IdP to return the email address of the current user +$settings->requestedNameIdFormat = OneLogin_Saml_Settings::NAMEID_EMAIL_ADDRESS; + +return $settings; diff --git a/demo/settings.php b/demo/settings.php deleted file mode 100644 index d3b268dc..00000000 --- a/demo/settings.php +++ /dev/null @@ -1,60 +0,0 @@ -idpSingleSignOnUrl = 'https://app.onelogin.com/saml/signon/6171'; - -// The certificate for the users account in the IdP -$settings->idpPublicCertificate = <<spReturnUrl = 'http://localhost/php-saml/consume.php'; - -// Name of this application -$settings->spIssuer = 'php-saml'; - -// Tells the IdP to return the email address of the current user -$settings->requestedNameIdFormat = OneLogin_Saml_Settings::NAMEID_EMAIL_ADDRESS; - -return $settings; \ No newline at end of file diff --git a/demo1/Readme.txt b/demo1/Readme.txt new file mode 100644 index 00000000..392ae176 --- /dev/null +++ b/demo1/Readme.txt @@ -0,0 +1,72 @@ +The example requires that SP and IdP are well configured before test it. + +SP setup +-------- + +The PHP Toolkit allows you to provide the settings info in 2 ways: + * Use a settings.php file that we should locate at the base folder of the + toolkit. + * Use an array with the setting data. + +In this demo we provide the data in the second way, using a setting array named + +Uses the settings_example.php included as a template to create the settings.php +settings and store it in the demo1 folder. Configure the SP part and later +review the metadata of the IdP and complete the IdP info. + +If you check the code of the index.php file you will see that the settings.php +file is loaded in order to get the $settingsInfo var to be used to initialize +the Setting class. + +Notice that in this demo, the setting.php file that could be defined at the base +folder of the toolkit is ignored and the libs are loaded using the _toolkit_loader.php located at the base folder of the toolkit. + + +IdP setup +--------- + +Once the SP is configured, the metadata of the SP is published at the +metadata.php file. Based on that info, configure the IdP. + + +How it works +------------ + + 1. First time you access to index.php view, you can select to login and return + to the same view or login and be redirected to the attrs.php view. + + 2. When you click: + + 2.1 in the first link, we access to (index.php?sso) an AuthNRequest + is sent to the IdP, we authenticate at the IdP and then a Response is sent + to the SP, specifically the Assertion Consumer Service view: index.php?acs, + notice that a RelayState parameter is set to the url that initiated the + process, the index.php view. + + 2.2 in the second link we access to (attrs.php) have the same process described at 2.1 with the difference that as RelayState is set the attrs.php + +3. The SAML Response is processed in the ACS (index.php?acs), if the Response + is not valid, the process stop here and a message is showed. Otherwise we + are redirected to the RelayState view. a) index.php or b) attrs.php + +4. We are logged in the app and the user attributes are showed. + At this point, we can test the single log out functionality. + +5. The single log out functionality could be tested by 2 ways. + + 5.1 SLO Initiated by SP. Click on the "logout" link at the SP, after that a + Logout Request is sent to the IdP, the session at the IdP is closed and replies to the SP a Logout Response (sent to the Single Logout Service + endpoint). The SLS endpoint (index.php?sls)of the SP process the Logout + Response and if is valid, close the user session of the local app. Notice + that the SLO Workflow starts and ends at the SP. + + 5.2 SLO Initiated by IdP. In this case, the action takes place on the IdP + side, the logout process is initiated at the idP, sends a Logout Request to the SP (SLS endpoint, index.php?sls). The SLS endpoint of the SP + process the Logout Request and if is valid, close the session of the user + at the local app and send a Logout Response to the IdP (to the SLS endpoint + of the IdP). The IdP receive the Logout Response, process it and close the + session at of the IdP. Notice that the SLO Workflow starts and ends at the IdP. + +Notice that all the SAML Requests and Responses are handler at a unique file, +the index.php file and how GET paramters are used to know the action that +must be done. diff --git a/demo1/attrs.php b/demo1/attrs.php new file mode 100644 index 00000000..9905e61a --- /dev/null +++ b/demo1/attrs.php @@ -0,0 +1,25 @@ +'; + echo ''; + foreach ($attributes as $attributeName => $attributeValues) { + echo ''; + } + echo '
NameValues
' . htmlentities($attributeName) . '
    '; + foreach ($attributeValues as $attributeValue) { + echo '
  • ' . htmlentities($attributeValue) . '
  • '; + } + echo '
'; + } else { + echo "

You don't have any attribute

"; + } + + echo '

Logout

'; +} else { + echo '

Login and access later to this page

'; +} diff --git a/demo1/index.php b/demo1/index.php new file mode 100644 index 00000000..4ec511f3 --- /dev/null +++ b/demo1/index.php @@ -0,0 +1,138 @@ +login(); + + # If AuthNRequest ID need to be saved in order to later validate it, do instead + # $ssoBuiltUrl = $auth->login(null, array(), false, false, true); + # $_SESSION['AuthNRequestID'] = $auth->getLastRequestID(); + # header('Pragma: no-cache'); + # header('Cache-Control: no-cache, must-revalidate'); + # header('Location: ' . $ssoBuiltUrl); + # exit(); + +} else if (isset($_GET['sso2'])) { + $returnTo = $spBaseUrl.'/demo1/attrs.php'; + $auth->login($returnTo); +} else if (isset($_GET['slo'])) { + $returnTo = null; + $parameters = array(); + $nameId = null; + $sessionIndex = null; + $nameIdFormat = null; + $samlNameIdNameQualifier = null; + $samlNameIdSPNameQualifier = null; + + if (isset($_SESSION['samlNameId'])) { + $nameId = $_SESSION['samlNameId']; + } + if (isset($_SESSION['samlNameIdFormat'])) { + $nameIdFormat = $_SESSION['samlNameIdFormat']; + } + if (isset($_SESSION['samlNameIdNameQualifier'])) { + $samlNameIdNameQualifier = $_SESSION['samlNameIdNameQualifier']; + } + if (isset($_SESSION['samlNameIdSPNameQualifier'])) { + $samlNameIdSPNameQualifier = $_SESSION['samlNameIdSPNameQualifier']; + } + if (isset($_SESSION['samlSessionIndex'])) { + $sessionIndex = $_SESSION['samlSessionIndex']; + } + + $auth->logout($returnTo, $parameters, $nameId, $sessionIndex, false, $nameIdFormat, $samlNameIdNameQualifier, $samlNameIdSPNameQualifier); + + # If LogoutRequest ID need to be saved in order to later validate it, do instead + # $sloBuiltUrl = $auth->logout(null, $parameters, $nameId, $sessionIndex, true); + # $_SESSION['LogoutRequestID'] = $auth->getLastRequestID(); + # header('Pragma: no-cache'); + # header('Cache-Control: no-cache, must-revalidate'); + # header('Location: ' . $sloBuiltUrl); + # exit(); + +} else if (isset($_GET['acs'])) { + if (isset($_SESSION) && isset($_SESSION['AuthNRequestID'])) { + $requestID = $_SESSION['AuthNRequestID']; + } else { + $requestID = null; + } + + $auth->processResponse($requestID); + + $errors = $auth->getErrors(); + + if (!empty($errors)) { + echo '

',implode(', ', $errors),'

'; + if ($auth->getSettings()->isDebugActive()) { + echo '

'.htmlentities($auth->getLastErrorReason()).'

'; + } + } + + if (!$auth->isAuthenticated()) { + echo "

Not authenticated

"; + exit(); + } + + $_SESSION['samlUserdata'] = $auth->getAttributes(); + $_SESSION['samlNameId'] = $auth->getNameId(); + $_SESSION['samlNameIdFormat'] = $auth->getNameIdFormat(); + $_SESSION['samlNameIdNameQualifier'] = $auth->getNameIdNameQualifier(); + $_SESSION['samlNameIdSPNameQualifier'] = $auth->getNameIdSPNameQualifier(); + $_SESSION['samlSessionIndex'] = $auth->getSessionIndex(); + unset($_SESSION['AuthNRequestID']); + if (isset($_POST['RelayState']) && OneLogin_Saml2_Utils::getSelfURL() != $_POST['RelayState']) { + // To avoid 'Open Redirect' attacks, before execute the + // redirection confirm the value of $_POST['RelayState'] is a // trusted URL. + $auth->redirectTo($_POST['RelayState']); + } +} else if (isset($_GET['sls'])) { + if (isset($_SESSION) && isset($_SESSION['LogoutRequestID'])) { + $requestID = $_SESSION['LogoutRequestID']; + } else { + $requestID = null; + } + + $auth->processSLO(false, $requestID); + $errors = $auth->getErrors(); + if (empty($errors)) { + echo '

Successfully logged out

'; + } else { + echo '

', htmlentities(implode(', ', $errors)), '

'; + if ($auth->getSettings()->isDebugActive()) { + echo '

'.htmlentities($auth->getLastErrorReason()).'

'; + } + } +} + +if (isset($_SESSION['samlUserdata'])) { + if (!empty($_SESSION['samlUserdata'])) { + $attributes = $_SESSION['samlUserdata']; + echo 'You have the following attributes:
'; + echo ''; + foreach ($attributes as $attributeName => $attributeValues) { + echo ''; + } + echo '
NameValues
' . htmlentities($attributeName) . '
    '; + foreach ($attributeValues as $attributeValue) { + echo '
  • ' . htmlentities($attributeValue) . '
  • '; + } + echo '
'; + } else { + echo "

You don't have any attribute

"; + } + + echo '

Logout

'; +} else { + echo '

Login

'; + echo '

Login and access to attrs.php page

'; +} diff --git a/demo1/metadata.php b/demo1/metadata.php new file mode 100644 index 00000000..60233859 --- /dev/null +++ b/demo1/metadata.php @@ -0,0 +1,29 @@ +getSettings(); + // Now we only validate SP settings + $settings = new OneLogin_Saml2_Settings($settingsInfo, true); + $metadata = $settings->getSPMetadata(); + $errors = $settings->validateMetadata($metadata); + if (empty($errors)) { + header('Content-Type: text/xml'); + echo $metadata; + } else { + throw new OneLogin_Saml2_Error( + 'Invalid SP metadata: '.implode(', ', $errors), + OneLogin_Saml2_Error::METADATA_SP_INVALID + ); + } +} catch (Exception $e) { + echo $e->getMessage(); +} diff --git a/demo1/settings_example.php b/demo1/settings_example.php new file mode 100644 index 00000000..4fd76159 --- /dev/null +++ b/demo1/settings_example.php @@ -0,0 +1,26 @@ +'; //or http:// + + $settingsInfo = array ( + 'sp' => array ( + 'entityId' => $spBaseUrl.'/demo1/metadata.php', + 'assertionConsumerService' => array ( + 'url' => $spBaseUrl.'/demo1/index.php?acs', + ), + 'singleLogoutService' => array ( + 'url' => $spBaseUrl.'/demo1/index.php?sls', + ), + 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:unspecified', + ), + 'idp' => array ( + 'entityId' => '', + 'singleSignOnService' => array ( + 'url' => '', + ), + 'singleLogoutService' => array ( + 'url' => '', + ), + 'x509cert' => '', + ), + ); diff --git a/demo2/Readme.txt b/demo2/Readme.txt new file mode 100644 index 00000000..1be1ab01 --- /dev/null +++ b/demo2/Readme.txt @@ -0,0 +1,76 @@ +The example requires that SP and IdP are well configured before test it. + +SP setup +-------- + +The PHP Toolkit allows you to provide the settings info in 2 ways: + * Use a settings.php file that we should locate at the base folder of the + toolkit. + * Use an array with the setting data. + +The first is the case of the demo2 app. The setting.php file and the +setting_extended.php file should be defined at the base folder of the toolkit. +Review the setting_example.php and the advanced_settings_example.php to +learn how to build them. + +In this case as Attribute Consume Service and Single Logout Service we gonna +use the files located in the endpoint folder (acs.php and sls.php). + +IdP setup +--------- + +Once the SP is configured, the metadata of the SP is published at the +metadata.php file. Based on that info, configure the IdP. + + +How it works +------------ + +At demo1, we saw how all the SAML Request and Responses were handler at an +unique file, the index.php file. This demo1 uses hight-level programming. + +At demo2, we have several views: index.php, sso.php, slo.php, consume.php +and metadata.php. As we said, we gonna use the endpoints that are defined +in the toolkit (acs.php, sls.php of the endpoints folder). This demo2 uses +low-level programming. + +Notice that the SSO action can be initiated at index.php or sso.php. + +The SAML workflow that take place is similar that the workflow defined in the +demo1, only changes the targets. + + + 1. When you first time access to index.php or sso.php, an AuthNRequest is + sent to the IdP automatically, (as RelayState is sent the origin url). + We authenticate at the IdP and then a Response is sent to the SP, to the + ACS endpoint, in this case acs.php of the endpoints folder. + + 2. The SAML Response is processed in the ACS, if the Response is not valid, + the process stop here and a message is showed. Otherwise we are redirected + to the RelayState view (sso.php or index.php). The sso.php detect if the + user is logged and do a redirect to index.php, so we will be in the + index.php at the end. + + 3. We are logged in the app and the user attributes are showed. + At this point, we can test the single log out functionality. + + 4. The single log out functionality could be tested by 2 ways. + + 4.1 SLO Initiated by SP. Click on the "logout" link at the SP, after that + we are redirected to the slo.php view and there a Logout Request is sent + to the IdP, the session at the IdP is closed and replies to the SP a + Logout Response (sent to the Single Logout Service endpoint). In this case + The SLS endpoint of the SP process the Logout Response and if is + valid, close the user session of the local app. Notice that the SLO + Workflow starts and ends at the SP. + + 5.2 SLO Initiated by IdP. In this case, the action takes place on the IdP + side, the logout process is initiated at the idP, sends a Logout + Request to the SP (SLS endpoint sls.php of the endpoint folder). + The SLS endpoint of the SP process the Logout Request and if is valid, + close the session of the user at the local app and sends a Logout Response + to the IdP (to the SLS endpoint of the IdP).The IdP receives the Logout + Response, process it and close the session at of the IdP. Notice that the + SLO Workflow starts and ends at the IdP. + + diff --git a/demo2/consume.php b/demo2/consume.php new file mode 100644 index 00000000..adff0aa7 --- /dev/null +++ b/demo2/consume.php @@ -0,0 +1,39 @@ +isValid()) { + echo 'You are: ' . htmlentities($samlResponse->getNameId()) . '
'; + $attributes = $samlResponse->getAttributes(); + if (!empty($attributes)) { + echo 'You have the following attributes:
'; + echo ''; + foreach ($attributes as $attributeName => $attributeValues) { + echo ''; + } + echo '
NameValues
' . htmlentities($attributeName) . '
    '; + foreach ($attributeValues as $attributeValue) { + echo '
  • ' . htmlentities($attributeValue) . '
  • '; + } + echo '
'; + } + } else { + echo 'Invalid SAML Response'; + } + } else { + echo 'No SAML Response found in POST.'; + } +} catch (Exception $e) { + echo 'Invalid SAML Response: ' . htmlentities($e->getMessage()); +} diff --git a/demo2/index.php b/demo2/index.php new file mode 100755 index 00000000..cea57e83 --- /dev/null +++ b/demo2/index.php @@ -0,0 +1,48 @@ +getRequest(); + + $parameters = array('SAMLRequest' => $samlRequest); + $parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfURLNoQuery(); + + $idpData = $settings->getIdPData(); + $ssoUrl = $idpData['singleSignOnService']['url']; + $url = OneLogin_Saml2_Utils::redirect($ssoUrl, $parameters, true); + + header("Location: $url"); +} else { + if (!empty($_SESSION['samlUserdata'])) { + $attributes = $_SESSION['samlUserdata']; + echo 'You have the following attributes:
'; + echo ''; + foreach ($attributes as $attributeName => $attributeValues) { + echo ''; + } + echo '
NameValues
' . htmlentities($attributeName) . '
    '; + foreach ($attributeValues as $attributeValue) { + echo '
  • ' . htmlentities($attributeValue) . '
  • '; + } + echo '
'; + if (!empty($_SESSION['IdPSessionIndex'])) { + echo '

The SessionIndex of the IdP is: '.htmlentities($_SESSION['IdPSessionIndex']).'

'; + } + } else { + echo "

You don't have any attribute

"; + } + echo '

Logout

'; +} diff --git a/demo2/metadata.php b/demo2/metadata.php new file mode 100644 index 00000000..49636a27 --- /dev/null +++ b/demo2/metadata.php @@ -0,0 +1,17 @@ +getSPData(); + +$samlMetadata = OneLogin_Saml2_Metadata::builder($sp); +echo $samlMetadata; diff --git a/demo2/slo.php b/demo2/slo.php new file mode 100644 index 00000000..4fa0cfb9 --- /dev/null +++ b/demo2/slo.php @@ -0,0 +1,34 @@ +getIdPData(); +if (isset($idpData['singleLogoutService']) && isset($idpData['singleLogoutService']['url'])) { + $sloUrl = $idpData['singleLogoutService']['url']; +} else { + throw new Exception("The IdP does not support Single Log Out"); +} + +if (isset($_SESSION['IdPSessionIndex']) && !empty($_SESSION['IdPSessionIndex'])) { + $logoutRequest = new OneLogin_Saml2_LogoutRequest($samlSettings, null, $_SESSION['IdPSessionIndex']); +} else { + $logoutRequest = new OneLogin_Saml2_LogoutRequest($samlSettings); +} + +$samlRequest = $logoutRequest->getRequest(); + +$parameters = array('SAMLRequest' => $samlRequest); + +$url = OneLogin_Saml2_Utils::redirect($sloUrl, $parameters, true); + +header("Location: $url"); diff --git a/demo2/sso.php b/demo2/sso.php new file mode 100644 index 00000000..cc95a771 --- /dev/null +++ b/demo2/sso.php @@ -0,0 +1,22 @@ +login(); +} else { + $indexUrl = str_replace('/sso.php', '/index.php', OneLogin_Saml2_Utils::getSelfURLNoQuery()); + OneLogin_Saml2_Utils::redirect($indexUrl); +} diff --git a/docs/SAML_PHPToolkit_Guide.pdf b/docs/SAML_PHPToolkit_Guide.pdf new file mode 100644 index 00000000..fd71438a Binary files /dev/null and b/docs/SAML_PHPToolkit_Guide.pdf differ diff --git a/docs/Saml2/.htaccess b/docs/Saml2/.htaccess new file mode 100644 index 00000000..7b01f9bf --- /dev/null +++ b/docs/Saml2/.htaccess @@ -0,0 +1,5 @@ +# Fixes a vulnerability in CentOS: http://stackoverflow.com/questions/20533279/prevent-php-from-parsing-non-php-files-such-as-somefile-php-txt + + RemoveHandler .php + ForceType text/plain + \ No newline at end of file diff --git a/docs/Saml2/checkstyle.xml b/docs/Saml2/checkstyle.xml new file mode 100644 index 00000000..cedb3813 --- /dev/null +++ b/docs/Saml2/checkstyle.xml @@ -0,0 +1,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_Auth.html b/docs/Saml2/classes/OneLogin_Saml2_Auth.html new file mode 100644 index 00000000..197258f0 --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_Auth.html @@ -0,0 +1,2085 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + + + +
+
+

Properties

+
+ +
+ +
+
+ + +
+ +
+ +
+
+ +
+

$_attributes

+
$_attributes : array
+

User attributes data.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_attributesWithFriendlyName

+
$_attributesWithFriendlyName : array
+

User attributes data with FriendlyName index.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_nameid

+
$_nameid : string
+

NameID

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_nameidFormat

+
$_nameidFormat : string
+

NameID Format

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_nameidNameQualifier

+
$_nameidNameQualifier : string
+

NameID NameQualifier

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_nameidSPNameQualifier

+
$_nameidSPNameQualifier : string
+

NameID SP NameQualifier

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_authenticated

+
$_authenticated : boolean
+

If user is authenticated.

+ + +

Type

+ boolean +
+
+ +
+ +
+
+ +
+

$_sessionIndex

+
$_sessionIndex : string
+

SessionIndex. When the user is logged, this stored it +from the AuthnStatement of the SAML Response

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_sessionExpiration

+
$_sessionExpiration : integer|null
+

SessionNotOnOrAfter. When the user is logged, this stored it +from the AuthnStatement of the SAML Response

+ + +

Type

+ integer|null +
+
+ +
+ +
+
+ +
+

$_lastMessageId

+
$_lastMessageId : string
+

The ID of the last message processed

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_lastAssertionId

+
$_lastAssertionId : string
+

The ID of the last assertion processed

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_lastAssertionNotOnOrAfter

+
$_lastAssertionNotOnOrAfter : integer
+

The NotOnOrAfter value of the valid SubjectConfirmationData +node (if any) of the last assertion processed

+ + +

Type

+ integer +
+
+ +
+ +
+
+ +
+

$_errors

+
$_errors : array
+

If any error.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_errorReason

+
$_errorReason : string|null
+

Reason of the last error.

+ + +

Type

+ string|null +
+
+ +
+ +
+
+ +
+

$_lastRequestID

+
$_lastRequestID : string
+

Last AuthNRequest ID or LogoutRequest ID generated by this Service Provider

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_lastRequest

+
$_lastRequest : string
+

The most recently-constructed/processed XML SAML request +(AuthNRequest, LogoutRequest)

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_lastResponse

+
$_lastResponse : string|\DomDocument|null
+

The most recently-constructed/processed XML SAML response +(SAMLResponse, LogoutResponse). If the SAMLResponse was +encrypted, by default tries to return the decrypted XML

+ + +

Type

+ string|\DomDocument|null +
+
+ +
+ + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(array|object|null  $oldSettings = null, boolean  $spValidationOnly = false) 
+

Initializes the SP SAML instance.

+ + +

Parameters

+ + + + + + + + + + + +
array|object|null$oldSettings

Setting data (You can provide a OneLogin_Saml_Settings, the settings object of the Saml folder implementation)

boolean$spValidationOnly

if you only as an SP , you should set it to false if not you should set it to true

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ + +
+
+ +
+ +
+
+ +
+

getSettings()

+ +
getSettings() : \OneLogin_Saml2_Settings
+

Returns the settings info

+ + + + +

Returns

+ \OneLogin_Saml2_Settings + —

The settings data.

+ +
+
+ +
+ +
+
+ +
+

setStrict()

+ +
setStrict(boolean  $value) 
+

Set the strict mode active/disable

+ + +

Parameters

+ + + + + + +
boolean$value

Strict parameter

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ + +
+
+ +
+ +
+
+ +
+

setSchemasPath()

+ +
setSchemasPath(string  $path) : $this
+

Set schemas path

+ + +

Parameters

+ + + + + + +
string$path
+ + +

Returns

+ $this + +
+
+ +
+ +
+
+ +
+

processResponse()

+ +
processResponse(string|null  $requestId = null) 
+

Process the SAML Response sent by the IdP.

+ + +

Parameters

+ + + + + + +
string|null$requestId

The ID of the AuthNRequest sent by this SP to the IdP

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
\OneLogin_Saml2_ValidationError
+
+
+ + +
+
+ +
+ +
+
+ +
+

processSLO()

+ +
processSLO(boolean  $keepLocalSession = false, string|null  $requestId = null, boolean  $retrieveParametersFromServer = false, callable  $cbDeleteSession = null, boolean  $stay = false) : string|null
+

Process the SAML Logout Response / Logout Request sent by the IdP.

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
boolean$keepLocalSession

When false will destroy the local session, otherwise will keep it

string|null$requestId

The ID of the LogoutRequest sent by this SP to the IdP

boolean$retrieveParametersFromServer

True if we want to use parameters from $_SERVER to validate the signature

callable$cbDeleteSession

Callback to be executed to delete session

boolean$stay

True if we want to stay (returns the url string) False to redirect

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string|null + +
+
+ +
+ +
+
+ +
+

redirectTo()

+ +
redirectTo(string  $url = '', array  $parameters = array(), boolean  $stay = false) : string|null
+

Redirects the user to the url past by parameter +or to the url that we defined in our SSO Request.

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$url

The target URL to redirect the user.

array$parameters

Extra parameters to be passed as part of the url

boolean$stay

True if we want to stay (returns the url string) False to redirect

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string|null + +
+
+ +
+ +
+
+ +
+

isAuthenticated()

+ +
isAuthenticated() : boolean
+

Checks if the user is authenticated or not.

+ + + + +

Returns

+ boolean + —

True if the user is authenticated

+ +
+
+ +
+ +
+
+ +
+

getAttributes()

+ +
getAttributes() : array
+

Returns the set of SAML attributes.

+ + + + +

Returns

+ array + —

Attributes of the user.

+ +
+
+ +
+ +
+
+ +
+

getAttributesWithFriendlyName()

+ +
getAttributesWithFriendlyName() : array
+

Returns the set of SAML attributes indexed by FriendlyName

+ + + + +

Returns

+ array + —

Attributes of the user.

+ +
+
+ +
+ +
+
+ +
+

getNameId()

+ +
getNameId() : string
+

Returns the nameID

+ + + + +

Returns

+ string + —

The nameID of the assertion

+ +
+
+ +
+ +
+
+ +
+

getNameIdFormat()

+ +
getNameIdFormat() : string
+

Returns the nameID Format

+ + + + +

Returns

+ string + —

The nameID Format of the assertion

+ +
+
+ +
+ +
+
+ +
+

getNameIdNameQualifier()

+ +
getNameIdNameQualifier() : string
+

Returns the nameID NameQualifier

+ + + + +

Returns

+ string + —

The nameID NameQualifier of the assertion

+ +
+
+ +
+ +
+
+ +
+

getNameIdSPNameQualifier()

+ +
getNameIdSPNameQualifier() : string
+

Returns the nameID SP NameQualifier

+ + + + +

Returns

+ string + —

The nameID SP NameQualifier of the assertion

+ +
+
+ +
+ +
+
+ +
+

getSessionIndex()

+ +
getSessionIndex() : string|null
+

Returns the SessionIndex

+ + + + +

Returns

+ string|null + —

The SessionIndex of the assertion

+ +
+
+ +
+ +
+
+ +
+

getSessionExpiration()

+ +
getSessionExpiration() : integer|null
+

Returns the SessionNotOnOrAfter

+ + + + +

Returns

+ integer|null + —

The SessionNotOnOrAfter of the assertion

+ +
+
+ +
+ +
+
+ +
+

getErrors()

+ +
getErrors() : array
+

Returns if there were any error

+ + + + +

Returns

+ array + —

Errors

+ +
+
+ +
+ +
+
+ +
+

getLastErrorReason()

+ +
getLastErrorReason() : string|null
+

Returns the reason for the last error

+ + + + +

Returns

+ string|null + —

Error reason

+ +
+
+ +
+ +
+
+ +
+

getAttribute()

+ +
getAttribute(string  $name) : array|null
+

Returns the requested SAML attribute

+ + +

Parameters

+ + + + + + +
string$name

The requested attribute of the user.

+ + +

Returns

+ array|null + —

Requested SAML attribute ($name).

+ +
+
+ +
+ +
+
+ +
+

getAttributeWithFriendlyName()

+ +
getAttributeWithFriendlyName(string  $friendlyName) : array|null
+

Returns the requested SAML attribute indexed by FriendlyName

+ + +

Parameters

+ + + + + + +
string$friendlyName

The requested attribute of the user.

+ + +

Returns

+ array|null + —

Requested SAML attribute ($friendlyName).

+ +
+
+ +
+ +
+
+ +
+

login()

+ +
login(string|null  $returnTo = null, array  $parameters = array(), boolean  $forceAuthn = false, boolean  $isPassive = false, boolean  $stay = false, boolean  $setNameIdPolicy = true, string  $nameIdValueReq = null) : string|null
+

Initiates the SSO process.

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
string|null$returnTo

The target URL the user should be returned to after login.

array$parameters

Extra parameters to be added to the GET

boolean$forceAuthn

When true the AuthNRequest will set the ForceAuthn='true'

boolean$isPassive

When true the AuthNRequest will set the Ispassive='true'

boolean$stay

True if we want to stay (returns the url string) False to redirect

boolean$setNameIdPolicy

When true the AuthNRueqest will set a nameIdPolicy element

string$nameIdValueReq

Indicates to the IdP the subject that should be authenticated

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string|null + —

If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters

+ +
+
+ +
+ +
+
+ +
+

logout()

+ +
logout(string|null  $returnTo = null, array  $parameters = array(), string|null  $nameId = null, string|null  $sessionIndex = null, boolean  $stay = false, string|null  $nameIdFormat = null, string|null  $nameIdNameQualifier = null,   $nameIdSPNameQualifier = null) : string|null
+

Initiates the SLO process.

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
string|null$returnTo

The target URL the user should be returned to after logout.

array$parameters

Extra parameters to be added to the GET

string|null$nameId

The NameID that will be set in the LogoutRequest.

string|null$sessionIndex

The SessionIndex (taken from the SAML Response in the SSO process).

boolean$stay

True if we want to stay (returns the url string) False to redirect

string|null$nameIdFormat

The NameID Format will be set in the LogoutRequest.

string|null$nameIdNameQualifier

The NameID NameQualifier will be set in the LogoutRequest.

$nameIdSPNameQualifier
+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string|null + —

If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters

+ +
+
+ +
+ +
+
+ +
+

getSSOurl()

+ +
getSSOurl() : string
+

Gets the IdP SSO url.

+ + + + +

Returns

+ string + —

The url of the IdP Single Sign On Service

+ +
+
+ +
+ +
+
+ +
+

getSLOurl()

+ +
getSLOurl() : string|null
+

Gets the IdP SLO url.

+ + + + +

Returns

+ string|null + —

The url of the IdP Single Logout Service

+ +
+
+ +
+ +
+
+ +
+

getSLOResponseUrl()

+ +
getSLOResponseUrl() : string|null
+

Gets the IdP SLO response url.

+ + + + +

Returns

+ string|null + —

The response url of the IdP Single Logout Service

+ +
+
+ +
+ +
+
+ +
+

getLastRequestID()

+ +
getLastRequestID() : string
+

Gets the ID of the last AuthNRequest or LogoutRequest generated by the Service Provider.

+ + + + +

Returns

+ string + —

The ID of the Request SAML message.

+ +
+
+ +
+ +
+
+ +
+

buildRequestSignature()

+ +
buildRequestSignature(string  $samlRequest, string  $relayState, string  $signAlgorithm = \XMLSecurityKey::RSA_SHA1) : string
+

Generates the Signature for a SAML Request

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$samlRequest

The SAML Request

string$relayState

The RelayState

string$signAlgorithm

Signature algorithm method

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string + —

A base64 encoded signature

+ +
+
+ +
+ +
+
+ +
+

buildResponseSignature()

+ +
buildResponseSignature(string  $samlResponse, string  $relayState, string  $signAlgorithm = \XMLSecurityKey::RSA_SHA1) : string
+

Generates the Signature for a SAML Response

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$samlResponse

The SAML Response

string$relayState

The RelayState

string$signAlgorithm

Signature algorithm method

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string + —

A base64 encoded signature

+ +
+
+ +
+ +
+
+ +
+

getLastMessageId()

+ +
getLastMessageId() : string
+

+ + + + +

Returns

+ string + —

The ID of the last message processed

+ +
+
+ +
+ +
+
+ +
+

getLastAssertionId()

+ +
getLastAssertionId() : string
+

+ + + + +

Returns

+ string + —

The ID of the last assertion processed

+ +
+
+ +
+ +
+
+ +
+

getLastAssertionNotOnOrAfter()

+ +
getLastAssertionNotOnOrAfter() : integer
+

+ + + + +

Returns

+ integer + —

The NotOnOrAfter value of the valid +SubjectConfirmationData node (if any) +of the last assertion processed

+ +
+
+ +
+ +
+
+ +
+

getLastRequestXML()

+ +
getLastRequestXML() : string
+

Returns the most recently-constructed/processed +XML SAML request (AuthNRequest, LogoutRequest)

+ + + + +

Returns

+ string + —

The Request XML

+ +
+
+ +
+ +
+
+ +
+

getLastResponseXML()

+ +
getLastResponseXML() : string|null
+

Returns the most recently-constructed/processed +XML SAML response (SAMLResponse, LogoutResponse).

+

If the SAMLResponse was encrypted, by default tries +to return the decrypted XML.

+ + + +

Returns

+ string|null + —

The Response XML

+ +
+
+ +
+ +
+
+ +
+

buildMessageSignature()

+ +
buildMessageSignature(string  $samlMessage, string  $relayState, string  $signAlgorithm = \XMLSecurityKey::RSA_SHA256, string  $type = "SAMLRequest") : string
+

Generates the Signature for a SAML Response

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + +
string$samlMessage

The SAML Response

string$relayState

The RelayState

string$signAlgorithm

Signature algorithm method

string$type

"SAMLRequest" or "SAMLResponse"

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string + —

A base64 encoded signature

+ +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_AuthnRequest.html b/docs/Saml2/classes/OneLogin_Saml2_AuthnRequest.html new file mode 100644 index 00000000..fe64ea2b --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_AuthnRequest.html @@ -0,0 +1,549 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_AuthnRequest

+

SAML 2 Authentication Request

+ + + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ __construct()
+ getRequest()
+ getId()
+ getXML()
+
+
+ No public properties found +
+
+ No constants found +
+
+
+
+ No protected methods found +
+
+ $_settings
+
+
+ N/A +
+
+
+
+ No private methods found +
+
+ $_authnRequest
+ $_id
+
+
+ N/A +
+
+
+
+ +
+ + + +
+
+

Properties

+
+ +
+ +
+
+ +
+

$_settings

+
$_settings : \OneLogin_Saml2_Settings
+

Object that represents the setting info

+ + +

Type

+ \OneLogin_Saml2_Settings +
+
+ +
+ +
+
+ +
+

$_authnRequest

+
$_authnRequest : string
+

SAML AuthNRequest string

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_id

+
$_id : string
+

SAML AuthNRequest ID.

+ + +

Type

+ string +
+
+ +
+ + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(\OneLogin_Saml2_Settings  $settings, boolean  $forceAuthn = false, boolean  $isPassive = false, boolean  $setNameIdPolicy = true, string  $nameIdValueReq = null) 
+

Constructs the AuthnRequest object.

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
\OneLogin_Saml2_Settings$settings

Settings

boolean$forceAuthn

When true the AuthNReuqest will set the ForceAuthn='true'

boolean$isPassive

When true the AuthNReuqest will set the Ispassive='true'

boolean$setNameIdPolicy

When true the AuthNReuqest will set a nameIdPolicy

string$nameIdValueReq

Indicates to the IdP the subject that should be authenticated

+ + + +
+
+ +
+ +
+
+ +
+

getRequest()

+ +
getRequest(boolean|null  $deflate = null) : string
+

Returns deflated, base64 encoded, unsigned AuthnRequest.

+ + +

Parameters

+ + + + + + +
boolean|null$deflate

Whether or not we should 'gzdeflate' the request body before we return it.

+ + +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

getId()

+ +
getId() : string
+

Returns the AuthNRequest ID.

+ + + + +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

getXML()

+ +
getXML() : string
+

Returns the XML that will be sent as part of the request

+ + + + +

Returns

+ string + +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_Constants.html b/docs/Saml2/classes/OneLogin_Saml2_Constants.html new file mode 100644 index 00000000..c27bad1b --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_Constants.html @@ -0,0 +1,1332 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_Constants

+

Constants of PHP Toolkit

+

Defines all required constants

+ + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ No public methods found +
+
+ No public properties found +
+
+ ALLOWED_CLOCK_DRIFT
+ NAMEID_EMAIL_ADDRESS
+ NAMEID_X509_SUBJECT_NAME
+ NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME
+ NAMEID_UNSPECIFIED
+ NAMEID_KERBEROS
+ NAMEID_ENTITY
+ NAMEID_TRANSIENT
+ NAMEID_PERSISTENT
+ NAMEID_ENCRYPTED
+ ATTRNAME_FORMAT_UNSPECIFIED
+ ATTRNAME_FORMAT_URI
+ ATTRNAME_FORMAT_BASIC
+ NS_SAML
+ NS_SAMLP
+ NS_SOAP
+ NS_MD
+ NS_XS
+ NS_XSI
+ NS_XENC
+ NS_DS
+ BINDING_HTTP_POST
+ BINDING_HTTP_REDIRECT
+ BINDING_HTTP_ARTIFACT
+ BINDING_SOAP
+ BINDING_DEFLATE
+ AC_UNSPECIFIED
+ AC_PASSWORD
+ AC_PASSWORD_PROTECTED
+ AC_X509
+ AC_SMARTCARD
+ AC_SMARTCARD_PKI
+ AC_KERBEROS
+ AC_WINDOWS
+ AC_TLS
+ AC_RSATOKEN
+ CM_BEARER
+ CM_HOLDER_KEY
+ CM_SENDER_VOUCHES
+ STATUS_SUCCESS
+ STATUS_REQUESTER
+ STATUS_RESPONDER
+ STATUS_VERSION_MISMATCH
+ STATUS_NO_PASSIVE
+ STATUS_PARTIAL_LOGOUT
+ STATUS_PROXY_COUNT_EXCEEDED
+
+
+
+
+ No protected methods found +
+
+ No protected properties found +
+
+ N/A +
+
+
+
+ No private methods found +
+
+ No private properties found +
+
+ N/A +
+
+
+
+ +
+ + +
+
+

Constants

+
+ +
+ +
+
+ +
+

ALLOWED_CLOCK_DRIFT

+
ALLOWED_CLOCK_DRIFT
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_EMAIL_ADDRESS

+
NAMEID_EMAIL_ADDRESS
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_X509_SUBJECT_NAME

+
NAMEID_X509_SUBJECT_NAME
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME

+
NAMEID_WINDOWS_DOMAIN_QUALIFIED_NAME
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_UNSPECIFIED

+
NAMEID_UNSPECIFIED
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_KERBEROS

+
NAMEID_KERBEROS
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_ENTITY

+
NAMEID_ENTITY
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_TRANSIENT

+
NAMEID_TRANSIENT
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_PERSISTENT

+
NAMEID_PERSISTENT
+

+ +
+
+ +
+ +
+
+ +
+

NAMEID_ENCRYPTED

+
NAMEID_ENCRYPTED
+

+ +
+
+ +
+ +
+
+ +
+

ATTRNAME_FORMAT_UNSPECIFIED

+
ATTRNAME_FORMAT_UNSPECIFIED
+

+ +
+
+ +
+ +
+
+ +
+

ATTRNAME_FORMAT_URI

+
ATTRNAME_FORMAT_URI
+

+ +
+
+ +
+ +
+
+ +
+

ATTRNAME_FORMAT_BASIC

+
ATTRNAME_FORMAT_BASIC
+

+ +
+
+ +
+ +
+
+ +
+

NS_SAML

+
NS_SAML
+

+ +
+
+ +
+ +
+
+ +
+

NS_SAMLP

+
NS_SAMLP
+

+ +
+
+ +
+ +
+
+ +
+

NS_SOAP

+
NS_SOAP
+

+ +
+
+ +
+ +
+
+ +
+

NS_MD

+
NS_MD
+

+ +
+
+ +
+ +
+
+ +
+

NS_XS

+
NS_XS
+

+ +
+
+ +
+ +
+
+ +
+

NS_XSI

+
NS_XSI
+

+ +
+
+ +
+ +
+
+ +
+

NS_XENC

+
NS_XENC
+

+ +
+
+ +
+ +
+
+ +
+

NS_DS

+
NS_DS
+

+ +
+
+ +
+ +
+
+ +
+

BINDING_HTTP_POST

+
BINDING_HTTP_POST
+

+ +
+
+ +
+ +
+
+ +
+

BINDING_HTTP_REDIRECT

+
BINDING_HTTP_REDIRECT
+

+ +
+
+ +
+ +
+
+ +
+

BINDING_HTTP_ARTIFACT

+
BINDING_HTTP_ARTIFACT
+

+ +
+
+ +
+ +
+
+ +
+

BINDING_SOAP

+
BINDING_SOAP
+

+ +
+
+ +
+ +
+
+ +
+

BINDING_DEFLATE

+
BINDING_DEFLATE
+

+ +
+
+ +
+ +
+
+ +
+

AC_UNSPECIFIED

+
AC_UNSPECIFIED
+

+ +
+
+ +
+ +
+
+ +
+

AC_PASSWORD

+
AC_PASSWORD
+

+ +
+
+ +
+ +
+
+ +
+

AC_PASSWORD_PROTECTED

+
AC_PASSWORD_PROTECTED
+

+ +
+
+ +
+ +
+
+ +
+

AC_X509

+
AC_X509
+

+ +
+
+ +
+ +
+
+ +
+

AC_SMARTCARD

+
AC_SMARTCARD
+

+ +
+
+ +
+ +
+
+ +
+

AC_SMARTCARD_PKI

+
AC_SMARTCARD_PKI
+

+ +
+
+ +
+ +
+
+ +
+

AC_KERBEROS

+
AC_KERBEROS
+

+ +
+
+ +
+ +
+
+ +
+

AC_WINDOWS

+
AC_WINDOWS
+

+ +
+
+ +
+ +
+
+ +
+

AC_TLS

+
AC_TLS
+

+ +
+
+ +
+ +
+
+ +
+

AC_RSATOKEN

+
AC_RSATOKEN
+

+ +
+
+ +
+ +
+
+ +
+

CM_BEARER

+
CM_BEARER
+

+ +
+
+ +
+ +
+
+ +
+

CM_HOLDER_KEY

+
CM_HOLDER_KEY
+

+ +
+
+ +
+ +
+
+ +
+

CM_SENDER_VOUCHES

+
CM_SENDER_VOUCHES
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_SUCCESS

+
STATUS_SUCCESS
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_REQUESTER

+
STATUS_REQUESTER
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_RESPONDER

+
STATUS_RESPONDER
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_VERSION_MISMATCH

+
STATUS_VERSION_MISMATCH
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_NO_PASSIVE

+
STATUS_NO_PASSIVE
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_PARTIAL_LOGOUT

+
STATUS_PARTIAL_LOGOUT
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_PROXY_COUNT_EXCEEDED

+
STATUS_PROXY_COUNT_EXCEEDED
+

+ +
+
+ +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_Error.html b/docs/Saml2/classes/OneLogin_Saml2_Error.html new file mode 100644 index 00000000..81029db8 --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_Error.html @@ -0,0 +1,724 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_Error

+

Error class of PHP Toolkit

+

Defines the Error class

+ + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ __construct()
+
+
+ No public properties found +
+
+ SETTINGS_FILE_NOT_FOUND
+ SETTINGS_INVALID_SYNTAX
+ SETTINGS_INVALID
+ METADATA_SP_INVALID
+ SP_CERTS_NOT_FOUND
+ CERT_NOT_FOUND
+ REDIRECT_INVALID_URL
+ PUBLIC_CERT_FILE_NOT_FOUND
+ PRIVATE_KEY_FILE_NOT_FOUND
+ SAML_RESPONSE_NOT_FOUND
+ SAML_LOGOUTMESSAGE_NOT_FOUND
+ SAML_LOGOUTREQUEST_INVALID
+ SAML_LOGOUTRESPONSE_INVALID
+ SAML_SINGLE_LOGOUT_NOT_SUPPORTED
+ PRIVATE_KEY_NOT_FOUND
+ UNSUPPORTED_SETTINGS_OBJECT
+
+
+
+
+ No protected methods found +
+
+ No protected properties found +
+
+ N/A +
+
+
+
+ No private methods found +
+
+ No private properties found +
+
+ N/A +
+
+
+
+ +
+ + +
+
+

Constants

+
+ +
+ +
+
+ +
+

SETTINGS_FILE_NOT_FOUND

+
SETTINGS_FILE_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

SETTINGS_INVALID_SYNTAX

+
SETTINGS_INVALID_SYNTAX
+

+ +
+
+ +
+ +
+
+ +
+

SETTINGS_INVALID

+
SETTINGS_INVALID
+

+ +
+
+ +
+ +
+
+ +
+

METADATA_SP_INVALID

+
METADATA_SP_INVALID
+

+ +
+
+ +
+ +
+
+ +
+

SP_CERTS_NOT_FOUND

+
SP_CERTS_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

CERT_NOT_FOUND

+
CERT_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

REDIRECT_INVALID_URL

+
REDIRECT_INVALID_URL
+

+ +
+
+ +
+ +
+
+ +
+

PUBLIC_CERT_FILE_NOT_FOUND

+
PUBLIC_CERT_FILE_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

PRIVATE_KEY_FILE_NOT_FOUND

+
PRIVATE_KEY_FILE_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

SAML_RESPONSE_NOT_FOUND

+
SAML_RESPONSE_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

SAML_LOGOUTMESSAGE_NOT_FOUND

+
SAML_LOGOUTMESSAGE_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

SAML_LOGOUTREQUEST_INVALID

+
SAML_LOGOUTREQUEST_INVALID
+

+ +
+
+ +
+ +
+
+ +
+

SAML_LOGOUTRESPONSE_INVALID

+
SAML_LOGOUTRESPONSE_INVALID
+

+ +
+
+ +
+ +
+
+ +
+

SAML_SINGLE_LOGOUT_NOT_SUPPORTED

+
SAML_SINGLE_LOGOUT_NOT_SUPPORTED
+

+ +
+
+ +
+ +
+
+ +
+

PRIVATE_KEY_NOT_FOUND

+
PRIVATE_KEY_NOT_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

UNSUPPORTED_SETTINGS_OBJECT

+
UNSUPPORTED_SETTINGS_OBJECT
+

+ +
+
+ +
+ + + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(string  $msg, integer  $code, array|null  $args = null) 
+

Constructor

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$msg

Describes the error.

integer$code

The code error (defined in the error class).

array|null$args

Arguments used in the message that describes the error.

+ + + +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_IdPMetadataParser.html b/docs/Saml2/classes/OneLogin_Saml2_IdPMetadataParser.html new file mode 100644 index 00000000..5c22a7db --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_IdPMetadataParser.html @@ -0,0 +1,555 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_IdPMetadataParser

+

IdP Metadata Parser of PHP Toolkit

+ + + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ parseRemoteXML()
+ parseFileXML()
+ parseXML()
+ injectIntoSettings()
+
+
+ No public properties found +
+
+ No constants found +
+
+
+
+ No protected methods found +
+
+ No protected properties found +
+
+ N/A +
+
+
+
+ No private methods found +
+
+ No private properties found +
+
+ N/A +
+
+
+
+ +
+ + + + +
+

Methods

+ +
+ +
+
+ +
+

parseRemoteXML()

+ +
parseRemoteXML(string  $url, string  $entityId = null, string  $desiredNameIdFormat = null, string  $desiredSSOBinding = \OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT, string  $desiredSLOBinding = \OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT) : array
+

Get IdP Metadata Info from URL

+

This class does not validate in any way the URL that is introduced, +make sure to validate it properly before use it in the parseRemoteXML +method in order to avoid security issues like SSRF attacks.

+ +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
string$url

URL where the IdP metadata is published

string$entityId

Entity Id of the desired IdP, if no +entity Id is provided and the XML +metadata contains more than one +IDPSSODescriptor, the first is returned

string$desiredNameIdFormat

If available on IdP metadata, use that nameIdFormat

string$desiredSSOBinding

Parse specific binding SSO endpoint.

string$desiredSLOBinding

Parse specific binding SLO endpoint.

+ + +

Returns

+ array + —

metadata info in php-saml settings format

+ +
+
+ +
+ +
+
+ +
+

parseFileXML()

+ +
parseFileXML(string  $filepath, string  $entityId = null, string  $desiredNameIdFormat = null, string  $desiredSSOBinding = \OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT, string  $desiredSLOBinding = \OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT) : array
+

Get IdP Metadata Info from File

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
string$filepath

File path

string$entityId

Entity Id of the desired IdP, if no +entity Id is provided and the XML +metadata contains more than one +IDPSSODescriptor, the first is returned

string$desiredNameIdFormat

If available on IdP metadata, use that nameIdFormat

string$desiredSSOBinding

Parse specific binding SSO endpoint.

string$desiredSLOBinding

Parse specific binding SLO endpoint.

+ + +

Returns

+ array + —

metadata info in php-saml settings format

+ +
+
+ +
+ +
+
+ +
+

parseXML()

+ +
parseXML(string  $xml, string  $entityId = null, string  $desiredNameIdFormat = null, string  $desiredSSOBinding = \OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT, string  $desiredSLOBinding = \OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT) : array
+

Get IdP Metadata Info from URL

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
string$xml

XML that contains IdP metadata

string$entityId

Entity Id of the desired IdP, if no +entity Id is provided and the XML +metadata contains more than one +IDPSSODescriptor, the first is returned

string$desiredNameIdFormat

If available on IdP metadata, use that nameIdFormat

string$desiredSSOBinding

Parse specific binding SSO endpoint.

string$desiredSLOBinding

Parse specific binding SLO endpoint.

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ array + —

metadata info in php-saml settings format

+ +
+
+ +
+ +
+
+ +
+

injectIntoSettings()

+ +
injectIntoSettings(array  $settings, array  $metadataInfo) : array
+

Inject metadata info into php-saml settings array

+ + +

Parameters

+ + + + + + + + + + + +
array$settings

php-saml settings array

array$metadataInfo

array metadata info

+ + +

Returns

+ array + —

settings

+ +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_LogoutRequest.html b/docs/Saml2/classes/OneLogin_Saml2_LogoutRequest.html new file mode 100644 index 00000000..f68e6f1b --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_LogoutRequest.html @@ -0,0 +1,865 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_LogoutRequest

+

SAML 2 Logout Request

+ + + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ __construct()
+ getRequest()
+ getID()
+ getNameIdData()
+ getNameId()
+ getIssuer()
+ getSessionIndexes()
+ isValid()
+ getError()
+ getXML()
+
+
+ $id
+
+
+ No constants found +
+
+
+
+ No protected methods found +
+
+ $_settings
+ $_logoutRequest
+
+
+ N/A +
+
+
+
+ No private methods found +
+
+ $_error
+
+
+ N/A +
+
+
+
+ +
+ + + +
+
+

Properties

+
+ +
+ +
+
+ +
+

$id

+
$id : string
+

Contains the ID of the Logout Request

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_settings

+
$_settings : \OneLogin_Saml2_Settings
+

Object that represents the setting info

+ + +

Type

+ \OneLogin_Saml2_Settings +
+
+ +
+ +
+
+ +
+

$_logoutRequest

+
$_logoutRequest : string
+

SAML Logout Request

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_error

+
$_error : string
+

After execute a validation process, this var contains the cause

+ + +

Type

+ string +
+
+ +
+ + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(\OneLogin_Saml2_Settings  $settings, string|null  $request = null, string|null  $nameId = null, string|null  $sessionIndex = null, string|null  $nameIdFormat = null, string|null  $nameIdNameQualifier = null, string|null  $nameIdSPNameQualifier = null) 
+

Constructs the Logout Request object.

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
\OneLogin_Saml2_Settings$settings

Settings

string|null$request

A UUEncoded Logout Request.

string|null$nameId

The NameID that will be set in the LogoutRequest.

string|null$sessionIndex

The SessionIndex (taken from the SAML Response in the SSO process).

string|null$nameIdFormat

The NameID Format will be set in the LogoutRequest.

string|null$nameIdNameQualifier

The NameID NameQualifier will be set in the LogoutRequest.

string|null$nameIdSPNameQualifier

The NameID SP NameQualifier will be set in the LogoutRequest.

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ + +
+
+ +
+ +
+
+ +
+

getRequest()

+ +
getRequest(boolean|null  $deflate = null) : string
+

Returns the Logout Request defated, base64encoded, unsigned

+ + +

Parameters

+ + + + + + +
boolean|null$deflate

Whether or not we should 'gzdeflate' the request body before we return it.

+ + +

Returns

+ string + —

Deflated base64 encoded Logout Request

+ +
+
+ +
+ +
+
+ +
+

getID()

+ +
getID(string|\DOMDocument  $request) : string
+

Returns the ID of the Logout Request.

+ + +

Parameters

+ + + + + + +
string|\DOMDocument$request

Logout Request Message

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string + —

ID

+ +
+
+ +
+ +
+
+ +
+

getNameIdData()

+ +
getNameIdData(string|\DOMDocument  $request, string|null  $key = null) : array
+

Gets the NameID Data of the the Logout Request.

+ + +

Parameters

+ + + + + + + + + + + +
string|\DOMDocument$request

Logout Request Message

string|null$key

The SP key

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + —

Name ID Data (Value, Format, NameQualifier, SPNameQualifier)

+ +
+
+ +
+ +
+
+ +
+

getNameId()

+ +
getNameId(string|\DOMDocument  $request, string|null  $key = null) : string
+

Gets the NameID of the Logout Request.

+ + +

Parameters

+ + + + + + + + + + + +
string|\DOMDocument$request

Logout Request Message

string|null$key

The SP key

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ string + —

Name ID Value

+ +
+
+ +
+ +
+
+ +
+

getIssuer()

+ +
getIssuer(string|\DOMDocument  $request) : string|null
+

Gets the Issuer of the Logout Request.

+ + +

Parameters

+ + + + + + +
string|\DOMDocument$request

Logout Request Message

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ string|null + —

$issuer The Issuer

+ +
+
+ +
+ +
+
+ +
+

getSessionIndexes()

+ +
getSessionIndexes(string|\DOMDocument  $request) : array
+

Gets the SessionIndexes from the Logout Request.

+

Notice: Our Constructor only support 1 SessionIndex but this parser +extracts an array of all the SessionIndex found on a +Logout Request, that could be many.

+ +

Parameters

+ + + + + + +
string|\DOMDocument$request

Logout Request Message

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ array + —

The SessionIndex value

+ +
+
+ +
+ +
+
+ +
+

isValid()

+ +
isValid(boolean  $retrieveParametersFromServer = false) : boolean
+

Checks if the Logout Request received is valid.

+ + +

Parameters

+ + + + + + +
boolean$retrieveParametersFromServer
+ + +

Returns

+ boolean + —

If the Logout Request is or not valid

+ +
+
+ +
+ +
+
+ +
+

getError()

+ +
getError() : string
+

After execute a validation process, if fails this method returns the cause

+ + + + +

Returns

+ string + —

Cause

+ +
+
+ +
+ +
+
+ +
+

getXML()

+ +
getXML() : string
+

Returns the XML that will be sent as part of the request +or that was received at the SP

+ + + + +

Returns

+ string + +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_LogoutResponse.html b/docs/Saml2/classes/OneLogin_Saml2_LogoutResponse.html new file mode 100644 index 00000000..6ce18eb6 --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_LogoutResponse.html @@ -0,0 +1,797 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_LogoutResponse

+

SAML 2 Logout Response

+ + + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ __construct()
+ getIssuer()
+ getStatus()
+ isValid()
+ build()
+ getResponse()
+ getError()
+ getId()
+ getXML()
+
+
+ $id
+ $document
+
+
+ No constants found +
+
+
+
+ No protected methods found +
+
+ $_settings
+ $_logoutResponse
+
+
+ N/A +
+
+
+
+ _query()
+
+
+ $_error
+
+
+ N/A +
+
+
+
+ +
+ + + +
+
+

Properties

+
+ +
+ +
+
+ +
+

$id

+
$id : string
+

Contains the ID of the Logout Response

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$document

+
$document : \DomDocument
+

A DOMDocument class loaded from the SAML LogoutResponse.

+ + +

Type

+ \DomDocument +
+
+ +
+ +
+
+ +
+

$_settings

+
$_settings : \OneLogin_Saml2_Settings
+

Object that represents the setting info

+ + +

Type

+ \OneLogin_Saml2_Settings +
+
+ +
+ +
+
+ +
+

$_logoutResponse

+
$_logoutResponse : string
+

The decoded, unprocessed XML response provided to the constructor.

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_error

+
$_error : string|null
+

After execute a validation process, if it fails, this var contains the cause

+ + +

Type

+ string|null +
+
+ +
+ + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(\OneLogin_Saml2_Settings  $settings, string|null  $response = null) 
+

Constructs a Logout Response object (Initialize params from settings and if provided +load the Logout Response.

+ + +

Parameters

+ + + + + + + + + + + +
\OneLogin_Saml2_Settings$settings

Settings.

string|null$response

An UUEncoded SAML Logout response from the IdP.

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ + +
+
+ +
+ +
+
+ +
+

getIssuer()

+ +
getIssuer() : string|null
+

Gets the Issuer of the Logout Response.

+ + + + +

Returns

+ string|null + —

$issuer The Issuer

+ +
+
+ +
+ +
+
+ +
+

getStatus()

+ +
getStatus() : string|null
+

Gets the Status of the Logout Response.

+ + + + +

Returns

+ string|null + —

The Status

+ +
+
+ +
+ +
+
+ +
+

isValid()

+ +
isValid(string|null  $requestId = null, boolean  $retrieveParametersFromServer = false) : boolean
+

Determines if the SAML LogoutResponse is valid

+ + +

Parameters

+ + + + + + + + + + + +
string|null$requestId

The ID of the LogoutRequest sent by this SP to the IdP

boolean$retrieveParametersFromServer
+ + +

Returns

+ boolean + —

Returns if the SAML LogoutResponse is or not valid

+ +
+
+ +
+ +
+
+ +
+

build()

+ +
build(string  $inResponseTo) 
+

Generates a Logout Response object.

+ + +

Parameters

+ + + + + + +
string$inResponseTo

InResponseTo value for the Logout Response.

+ + + +
+
+ +
+ +
+
+ +
+

getResponse()

+ +
getResponse(boolean|null  $deflate = null) : string
+

Returns a Logout Response object.

+ + +

Parameters

+ + + + + + +
boolean|null$deflate

Whether or not we should 'gzdeflate' the response body before we return it.

+ + +

Returns

+ string + —

Logout Response deflated and base64 encoded

+ +
+
+ +
+ +
+
+ +
+

getError()

+ +
getError() : string
+

After execute a validation process, if fails this method returns the cause.

+ + + + +

Returns

+ string + —

Cause

+ +
+
+ +
+ +
+
+ +
+

getId()

+ +
getId() : string
+

+ + + + +

Returns

+ string + —

the ID of the Response

+ +
+
+ +
+ +
+
+ +
+

getXML()

+ +
getXML() : string
+

Returns the XML that will be sent as part of the response +or that was received at the SP

+ + + + +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

_query()

+ +
_query(string  $query) : \DOMNodeList
+

Extracts a node from the DOMDocument (Logout Response Menssage)

+ + +

Parameters

+ + + + + + +
string$query

Xpath Expresion

+ + +

Returns

+ \DOMNodeList + —

The queried node

+ +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_Metadata.html b/docs/Saml2/classes/OneLogin_Saml2_Metadata.html new file mode 100644 index 00000000..f7932bf8 --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_Metadata.html @@ -0,0 +1,562 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_Metadata

+

Metadata lib of PHP Toolkit

+ + + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ builder()
+ signMetadata()
+ addX509KeyDescriptors()
+
+
+ No public properties found +
+
+ TIME_VALID
+ TIME_CACHED
+
+
+
+
+ No protected methods found +
+
+ No protected properties found +
+
+ N/A +
+
+
+
+ No private methods found +
+
+ No private properties found +
+
+ N/A +
+
+
+
+ +
+ + +
+
+

Constants

+
+ +
+ +
+
+ +
+

TIME_VALID

+
TIME_VALID
+

+ +
+
+ +
+ +
+
+ +
+

TIME_CACHED

+
TIME_CACHED
+

+ +
+
+ +
+ + + + +
+

Methods

+ +
+ +
+
+ +
+

builder()

+ +
builder(array  $sp, boolean|string  $authnsign = false, boolean|string  $wsign = false, \DateTime|null  $validUntil = null, integer|null  $cacheDuration = null, array  $contacts = array(), array  $organization = array(), array  $attributes = array()) : string
+

Generates the metadata of the SP based on the settings

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
array$sp

The SP data

boolean|string$authnsign

authnRequestsSigned attribute

boolean|string$wsign

wantAssertionsSigned attribute

\DateTime|null$validUntil

Metadata's valid time

integer|null$cacheDuration

Duration of the cache in seconds

array$contacts

Contacts info

array$organization

Organization ingo

array$attributes
+ + +

Returns

+ string + —

SAML Metadata XML

+ +
+
+ +
+ +
+
+ +
+

signMetadata()

+ +
signMetadata(string  $metadata, string  $key, string  $cert, string  $signAlgorithm = \XMLSecurityKey::RSA_SHA1, string  $digestAlgorithm = \XMLSecurityDSig::SHA1) : string
+

Signs the metadata with the key/cert provided

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
string$metadata

SAML Metadata XML

string$key

x509 key

string$cert

x509 cert

string$signAlgorithm

Signature algorithm method

string$digestAlgorithm

Digest algorithm method

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ string + —

Signed Metadata

+ +
+
+ +
+ +
+
+ +
+

addX509KeyDescriptors()

+ +
addX509KeyDescriptors(string  $metadata, string  $cert, boolean  $wantsEncrypted = true) : string
+

Adds the x509 descriptors (sign/encriptation) to the metadata +The same cert will be used for sign/encrypt

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$metadata

SAML Metadata XML

string$cert

x509 cert

boolean$wantsEncrypted

Whether to include the KeyDescriptor for encryption

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ string + —

Metadata with KeyDescriptors

+ +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_Response.html b/docs/Saml2/classes/OneLogin_Saml2_Response.html new file mode 100644 index 00000000..e97dc80d --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_Response.html @@ -0,0 +1,1514 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ + +
+ + + +
+
+

Properties

+
+ +
+ +
+
+ +
+

$response

+
$response : string
+

The decoded, unprocessed XML response provided to the constructor.

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$document

+
$document : \DomDocument
+

A DOMDocument class loaded from the SAML Response.

+ + +

Type

+ \DomDocument +
+
+ +
+ +
+
+ +
+

$decryptedDocument

+
$decryptedDocument : \DomDocument
+

A DOMDocument class loaded from the SAML Response (Decrypted).

+ + +

Type

+ \DomDocument +
+
+ +
+ +
+
+ +
+

$encrypted

+
$encrypted : boolean
+

The response contains an encrypted assertion.

+ + +

Type

+ boolean +
+
+ +
+ +
+
+ + +
+ +
+ +
+
+ +
+

$_error

+
$_error : string
+

After validation, if it fail this var has the cause of the problem

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_validSCDNotOnOrAfter

+
$_validSCDNotOnOrAfter : integer
+

NotOnOrAfter value of a valid SubjectConfirmationData node

+ + +

Type

+ integer +
+
+ +
+ + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(\OneLogin_Saml2_Settings  $settings, string  $response) 
+

Constructs the SAML Response object.

+ + +

Parameters

+ + + + + + + + + + + +
\OneLogin_Saml2_Settings$settings

Settings.

string$response

A UUEncoded SAML response from the IdP.

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
\OneLogin_Saml2_ValidationError
+
+
+ + +
+
+ +
+ +
+
+ +
+

isValid()

+ +
isValid(string|null  $requestId = null) : boolean
+

Determines if the SAML Response is valid using the certificate.

+ + +

Parameters

+ + + + + + +
string|null$requestId

The ID of the AuthNRequest sent by this SP to the IdP

+ + +

Returns

+ boolean + —

Validate the document

+ +
+
+ +
+ +
+
+ +
+

getId()

+ +
getId() : string|null
+

+ + + + +

Returns

+ string|null + —

the ID of the Response

+ +
+
+ +
+ +
+
+ +
+

getAssertionId()

+ +
getAssertionId() : string|null
+

+ + + +

Throws

+
+
\InvalidArgumentException
+
+
+ +

Returns

+ string|null + —

the ID of the assertion in the Response

+ +
+
+ +
+ +
+
+ +
+

getAssertionNotOnOrAfter()

+ +
getAssertionNotOnOrAfter() : integer
+

+ + + + +

Returns

+ integer + —

the NotOnOrAfter value of the valid SubjectConfirmationData +node if any

+ +
+
+ +
+ +
+
+ +
+

checkStatus()

+ +
checkStatus() 
+

Checks if the Status is success

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+

If status is not success

+
+ + +
+
+ +
+ +
+
+ +
+

checkOneCondition()

+ +
checkOneCondition() : boolean
+

Checks that the samlp:Response/saml:Assertion/saml:Conditions element exists and is unique.

+ + + + +

Returns

+ boolean + —

true if the Conditions element exists and is unique

+ +
+
+ +
+ +
+
+ +
+

checkOneAuthnStatement()

+ +
checkOneAuthnStatement() : boolean
+

Checks that the samlp:Response/saml:Assertion/saml:AuthnStatement element exists and is unique.

+ + + + +

Returns

+ boolean + —

true if the AuthnStatement element exists and is unique

+ +
+
+ +
+ +
+
+ +
+

getAudiences()

+ +
getAudiences() : array
+

Gets the audiences.

+ + + + +

Returns

+ array + —

@audience The valid audiences of the response

+ +
+
+ +
+ +
+
+ +
+

getIssuers()

+ +
getIssuers() : array
+

Gets the Issuers (from Response and Assertion).

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + —

@issuers The issuers of the assertion/response

+ +
+
+ +
+ +
+
+ +
+

getNameIdData()

+ +
getNameIdData() : array
+

Gets the NameID Data provided by the SAML response from the IdP.

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + —

Name ID Data (Value, Format, NameQualifier, SPNameQualifier)

+ +
+
+ +
+ +
+
+ +
+

getNameId()

+ +
getNameId() : string|null
+

Gets the NameID provided by the SAML response from the IdP.

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ string|null + —

Name ID Value

+ +
+
+ +
+ +
+
+ +
+

getNameIdFormat()

+ +
getNameIdFormat() : string|null
+

Gets the NameID Format provided by the SAML response from the IdP.

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ string|null + —

Name ID Format

+ +
+
+ +
+ +
+
+ +
+

getNameIdNameQualifier()

+ +
getNameIdNameQualifier() : string|null
+

Gets the NameID NameQualifier provided by the SAML response from the IdP.

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ string|null + —

Name ID NameQualifier

+ +
+
+ +
+ +
+
+ +
+

getNameIdSPNameQualifier()

+ +
getNameIdSPNameQualifier() : string|null
+

Gets the NameID SP NameQualifier provided by the SAML response from the IdP.

+ + + +

Throws

+
+
\ValidationError
+
+
+ +

Returns

+ string|null + —

NameID SP NameQualifier

+ +
+
+ +
+ +
+
+ +
+

getSessionNotOnOrAfter()

+ +
getSessionNotOnOrAfter() : integer|null
+

Gets the SessionNotOnOrAfter from the AuthnStatement.

+

Could be used to set the local session expiration

+ + +

Throws

+
+
\Exception
+
+
+ +

Returns

+ integer|null + —

The SessionNotOnOrAfter value

+ +
+
+ +
+ +
+
+ +
+

getSessionIndex()

+ +
getSessionIndex() : string|null
+

Gets the SessionIndex from the AuthnStatement.

+

Could be used to be stored in the local session in order +to be used in a future Logout Request that the SP could +send to the SP, to set what specific session must be deleted

+ + + +

Returns

+ string|null + —

The SessionIndex value

+ +
+
+ +
+ +
+
+ +
+

getAttributes()

+ +
getAttributes() : array
+

Gets the Attributes from the AttributeStatement element.

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + —

The attributes of the SAML Assertion

+ +
+
+ +
+ +
+
+ +
+

getAttributesWithFriendlyName()

+ +
getAttributesWithFriendlyName() : array
+

Gets the Attributes from the AttributeStatement element using their FriendlyName.

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + —

The attributes of the SAML Assertion

+ +
+
+ +
+ +
+
+ +
+

validateNumAssertions()

+ +
validateNumAssertions() : boolean
+

Verifies that the document only contains a single Assertion (encrypted or not).

+ + + + +

Returns

+ boolean + —

TRUE if the document passes.

+ +
+
+ +
+ +
+
+ +
+

processSignedElements()

+ +
processSignedElements() : array
+

Verifies the signature nodes: + - Checks that are Response or Assertion + - Check that IDs and reference URI are unique and consistent.

+ + + +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + —

Signed element tags

+ +
+
+ +
+ +
+
+ +
+

validateTimestamps()

+ +
validateTimestamps() : boolean
+

Verifies that the document is still valid according Conditions Element.

+ + + +

Throws

+
+
\Exception
+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ boolean + +
+
+ +
+ +
+
+ +
+

validateSignedElements()

+ +
validateSignedElements(  $signedElements) : boolean
+

Verifies that the document has the expected signed nodes.

+ + +

Parameters

+ + + + + + +
$signedElements
+ +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ boolean + +
+
+ +
+ +
+
+ +
+

getError()

+ +
getError() : string
+

After execute a validation process, if fails this method returns the cause

+ + + + +

Returns

+ string + —

Cause

+ +
+
+ +
+ +
+
+ +
+

getXMLDocument()

+ +
getXMLDocument() : \DomDocument
+

Returns the SAML Response document (If contains an encrypted assertion, decrypts it)

+ + + + +

Returns

+ \DomDocument + —

SAML Response

+ +
+
+ +
+ +
+
+ +
+

_queryAssertion()

+ +
_queryAssertion(string  $assertionXpath) : \DOMNodeList
+

Extracts a node from the DOMDocument (Assertion).

+ + +

Parameters

+ + + + + + +
string$assertionXpath

Xpath Expression

+ + +

Returns

+ \DOMNodeList + —

The queried node

+ +
+
+ +
+ +
+
+ +
+

_decryptAssertion()

+ +
_decryptAssertion(\DomNode  $dom) : \DOMDocument
+

Decrypts the Assertion (DOMDocument)

+ + +

Parameters

+ + + + + + +
\DomNode$dom

DomDocument

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ \DOMDocument + —

Decrypted Assertion

+ +
+
+ +
+ +
+
+ +
+

_getAttributesByKeyName()

+ +
_getAttributesByKeyName(string  $keyName = "Name") : array
+

+ + +

Parameters

+ + + + + + +
string$keyName
+ +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + +
+
+ +
+ +
+
+ +
+

_query()

+ +
_query(string  $query) : \DOMNodeList
+

Extracts nodes that match the query from the DOMDocument (Response Menssage)

+ + +

Parameters

+ + + + + + +
string$query

Xpath Expresion

+ + +

Returns

+ \DOMNodeList + —

The queried nodes

+ +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_Settings.html b/docs/Saml2/classes/OneLogin_Saml2_Settings.html new file mode 100644 index 00000000..02fb955f --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_Settings.html @@ -0,0 +1,2073 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+ + +
+ + + +
+
+

Properties

+
+ +
+ +
+
+ +
+

$_paths

+
$_paths : array
+

List of paths.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_baseurl

+
$_baseurl : string
+

+ + +

Type

+ string +
+
+ +
+ +
+
+ +
+

$_strict

+
$_strict : boolean
+

Strict. If active, PHP Toolkit will reject unsigned or unencrypted messages +if it expects them signed or encrypted. If not, the messages will be accepted +and some security issues will be also relaxed.

+ + +

Type

+ boolean +
+
+ +
+ +
+
+ +
+

$_debug

+
$_debug : boolean
+

Activate debug mode

+ + +

Type

+ boolean +
+
+ +
+ +
+
+ +
+

$_sp

+
$_sp : array
+

SP data.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_idp

+
$_idp : array
+

IdP data.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_compress

+
$_compress : array
+

Compression settings that determine +whether gzip compression should be used.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_security

+
$_security : array
+

Security Info related to the SP.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_contacts

+
$_contacts : array
+

Setting contacts.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_organization

+
$_organization : array
+

Setting organization.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_errors

+
$_errors : array
+

Setting errors.

+ + +

Type

+ array +
+
+ +
+ +
+
+ +
+

$_spValidationOnly

+
$_spValidationOnly : boolean
+

Setting errors.

+ + +

Type

+ boolean +
+
+ +
+ + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(array|object|null  $settings = null, boolean  $spValidationOnly = false) 
+

Initializes the settings: +- Sets the paths of the different folders +- Loads settings info from settings file or array/object provided

+ + +

Parameters

+ + + + + + + + + + + +
array|object|null$settings

SAML Toolkit Settings

boolean$spValidationOnly
+ +

Throws

+
+
\OneLogin_Saml2_Error
+

If any settings parameter is invalid

+
\Exception
+

If OneLogin_Saml2_Settings is incorrectly supplied

+
+ + +
+
+ +
+ +
+
+ +
+

getBasePath()

+ +
getBasePath() : string
+

Returns base path.

+ + + + +

Returns

+ string + —

The base toolkit folder path

+ +
+
+ +
+ +
+
+ +
+

getCertPath()

+ +
getCertPath() : string
+

Returns cert path.

+ + + + +

Returns

+ string + —

The cert folder path

+ +
+
+ +
+ +
+
+ +
+

getConfigPath()

+ +
getConfigPath() : string
+

Returns config path.

+ + + + +

Returns

+ string + —

The config folder path

+ +
+
+ +
+ +
+
+ +
+

getLibPath()

+ +
getLibPath() : string
+

Returns lib path.

+ + + + +

Returns

+ string + —

The library folder path

+ +
+
+ +
+ +
+
+ +
+

getExtLibPath()

+ +
getExtLibPath() : string
+

Returns external lib path.

+ + + + +

Returns

+ string + —

The external library folder path

+ +
+
+ +
+ +
+
+ +
+

getSchemasPath()

+ +
getSchemasPath() : string
+

Returns schema path.

+ + + + +

Returns

+ string + —

The external library folder path

+ +
+
+ +
+ +
+
+ +
+

setSchemasPath()

+ +
setSchemasPath(string  $path) : $this
+

Set schemas path

+ + +

Parameters

+ + + + + + +
string$path
+ + +

Returns

+ $this + +
+
+ +
+ +
+
+ +
+

checkSettings()

+ +
checkSettings(array  $settings) : array
+

Checks the settings info.

+ + +

Parameters

+ + + + + + +
array$settings

Array with settings data

+ + +

Returns

+ array + —

$errors Errors found on the settings data

+ +
+
+ +
+ +
+
+ +
+

checkCompressionSettings()

+ +
checkCompressionSettings(array  $settings) : array
+

Checks the compression settings info.

+ + +

Parameters

+ + + + + + +
array$settings

Array with settings data

+ + +

Returns

+ array + —

$errors Errors found on the settings data

+ +
+
+ +
+ +
+
+ +
+

checkIdPSettings()

+ +
checkIdPSettings(array  $settings) : array
+

Checks the IdP settings info.

+ + +

Parameters

+ + + + + + +
array$settings

Array with settings data

+ + +

Returns

+ array + —

$errors Errors found on the IdP settings data

+ +
+
+ +
+ +
+
+ +
+

checkSPSettings()

+ +
checkSPSettings(array  $settings) : array
+

Checks the SP settings info.

+ + +

Parameters

+ + + + + + +
array$settings

Array with settings data

+ + +

Returns

+ array + —

$errors Errors found on the SP settings data

+ +
+
+ +
+ +
+
+ +
+

checkSPCerts()

+ +
checkSPCerts() : boolean
+

Checks if the x509 certs of the SP exists and are valid.

+ + + + +

Returns

+ boolean + +
+
+ +
+ +
+
+ +
+

getSPkey()

+ +
getSPkey() : string
+

Returns the x509 private key of the SP.

+ + + + +

Returns

+ string + —

SP private key

+ +
+
+ +
+ +
+
+ +
+

getSPcert()

+ +
getSPcert() : string
+

Returns the x509 public cert of the SP.

+ + + + +

Returns

+ string + —

SP public cert

+ +
+
+ +
+ +
+
+ +
+

getSPcertNew()

+ +
getSPcertNew() : string
+

Returns the x509 public of the SP that is +planed to be used soon instead the other +public cert

+ + + + +

Returns

+ string + —

SP public cert New

+ +
+
+ +
+ +
+
+ +
+

getIdPData()

+ +
getIdPData() : array
+

Gets the IdP data.

+ + + + +

Returns

+ array + —

IdP info

+ +
+
+ +
+ +
+
+ +
+

getSPData()

+ +
getSPData() : array
+

Gets the SP data.

+ + + + +

Returns

+ array + —

SP info

+ +
+
+ +
+ +
+
+ +
+

getSecurityData()

+ +
getSecurityData() : array
+

Gets security data.

+ + + + +

Returns

+ array + —

SP info

+ +
+
+ +
+ +
+
+ +
+

getContacts()

+ +
getContacts() : array
+

Gets contact data.

+ + + + +

Returns

+ array + —

SP info

+ +
+
+ +
+ +
+
+ +
+

getOrganization()

+ +
getOrganization() : array
+

Gets organization data.

+ + + + +

Returns

+ array + —

SP info

+ +
+
+ +
+ +
+
+ +
+

shouldCompressRequests()

+ +
shouldCompressRequests() : boolean
+

Should SAML requests be compressed?

+ + + + +

Returns

+ boolean + —

Yes/No as True/False

+ +
+
+ +
+ +
+
+ +
+

shouldCompressResponses()

+ +
shouldCompressResponses() : boolean
+

Should SAML responses be compressed?

+ + + + +

Returns

+ boolean + —

Yes/No as True/False

+ +
+
+ +
+ +
+
+ +
+

getIdPSSOUrl()

+ +
getIdPSSOUrl() : string|null
+

Gets the IdP SSO url.

+ + + + +

Returns

+ string|null + —

The url of the IdP Single Sign On Service

+ +
+
+ +
+ +
+
+ +
+

getIdPSLOUrl()

+ +
getIdPSLOUrl() : string|null
+

Gets the IdP SLO url.

+ + + + +

Returns

+ string|null + —

The request url of the IdP Single Logout Service

+ +
+
+ +
+ +
+
+ +
+

getIdPSLOResponseUrl()

+ +
getIdPSLOResponseUrl() : string|null
+

Gets the IdP SLO response url.

+ + + + +

Returns

+ string|null + —

The response url of the IdP Single Logout Service

+ +
+
+ +
+ +
+
+ +
+

getSPMetadata()

+ +
getSPMetadata(boolean  $alwaysPublishEncryptionCert = false, \DateTime|null  $validUntil = null, integer|null  $cacheDuration = null) : string
+

Gets the SP metadata. The XML representation.

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
boolean$alwaysPublishEncryptionCert

When 'true', the returned metadata +will always include an 'encryption' KeyDescriptor. Otherwise, the 'encryption' +KeyDescriptor will only be included if $advancedSettings['security']['wantNameIdEncrypted'] +or $advancedSettings['security']['wantAssertionsEncrypted'] are enabled.

\DateTime|null$validUntil

Metadata's valid time

integer|null$cacheDuration

Duration of the cache in seconds

+ +

Throws

+
+
\Exception
+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string + —

SP metadata (xml)

+ +
+
+ +
+ +
+
+ +
+

validateMetadata()

+ +
validateMetadata(string  $xml) : Array
+

Validates an XML SP Metadata.

+ + +

Parameters

+ + + + + + +
string$xml

Metadata's XML that will be validate

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ Array + —

The list of found errors

+ +
+
+ +
+ +
+
+ +
+

formatIdPCert()

+ +
formatIdPCert() 
+

Formats the IdP cert.

+ + + + + +
+
+ +
+ +
+
+ +
+

formatIdPCertMulti()

+ +
formatIdPCertMulti() 
+

Formats the Multple IdP certs.

+ + + + + +
+
+ +
+ +
+
+ +
+

formatSPCert()

+ +
formatSPCert() 
+

Formats the SP cert.

+ + + + + +
+
+ +
+ +
+
+ +
+

formatSPCertNew()

+ +
formatSPCertNew() 
+

Formats the SP cert.

+ + + + + +
+
+ +
+ +
+
+ +
+

formatSPKey()

+ +
formatSPKey() 
+

Formats the SP private key.

+ + + + + +
+
+ +
+ +
+
+ +
+

getErrors()

+ +
getErrors() : array
+

Returns an array with the errors, the array is empty when the settings is ok.

+ + + + +

Returns

+ array + —

Errors

+ +
+
+ +
+ +
+
+ +
+

setStrict()

+ +
setStrict(boolean  $value) 
+

Activates or deactivates the strict mode.

+ + +

Parameters

+ + + + + + +
boolean$value

Strict parameter

+ +

Throws

+
+
\Exception
+
+
+ + +
+
+ +
+ +
+
+ +
+

isStrict()

+ +
isStrict() : boolean
+

Returns if the 'strict' mode is active.

+ + + + +

Returns

+ boolean + —

Strict parameter

+ +
+
+ +
+ +
+
+ +
+

isDebugActive()

+ +
isDebugActive() : boolean
+

Returns if the debug is active.

+ + + + +

Returns

+ boolean + —

Debug parameter

+ +
+
+ +
+ +
+
+ +
+

setBaseURL()

+ +
setBaseURL(  $baseurl) 
+

Set a baseurl value.

+ + +

Parameters

+ + + + + + +
$baseurl
+ + + +
+
+ +
+ +
+
+ +
+

getBaseURL()

+ +
getBaseURL() : null|string
+

Returns the baseurl set on the settings if any.

+ + + + +

Returns

+ null|string + —

The baseurl

+ +
+
+ +
+ +
+
+ +
+

setIdPCert()

+ +
setIdPCert(string  $cert) 
+

Sets the IdP certificate.

+ + +

Parameters

+ + + + + + +
string$cert

IdP certificate

+ + + +
+
+ +
+ +
+
+ +
+

_loadPaths()

+ +
_loadPaths() 
+

Sets the paths of the different folders

+ + + + + +
+
+ +
+ +
+
+ +
+

_loadSettingsFromArray()

+ +
_loadSettingsFromArray(array  $settings) : boolean
+

Loads settings info from a settings Array

+ + +

Parameters

+ + + + + + +
array$settings

SAML Toolkit Settings

+ + +

Returns

+ boolean + —

True if the settings info is valid

+ +
+
+ +
+ +
+
+ +
+

_loadSettingsFromFile()

+ +
_loadSettingsFromFile() : boolean
+

Loads settings info from the settings file

+ + + +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ boolean + —

True if the settings info is valid

+ +
+
+ +
+ +
+
+ +
+

_addDefaultValues()

+ +
_addDefaultValues() 
+

Add default values if the settings info is not complete

+ + + + + +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_Utils.html b/docs/Saml2/classes/OneLogin_Saml2_Utils.html new file mode 100644 index 00000000..20741819 --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_Utils.html @@ -0,0 +1,2498 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+ + + +
+
+

Constants

+
+ +
+ +
+
+ +
+

RESPONSE_SIGNATURE_XPATH

+
RESPONSE_SIGNATURE_XPATH
+

+ +
+
+ +
+ +
+
+ +
+

ASSERTION_SIGNATURE_XPATH

+
ASSERTION_SIGNATURE_XPATH
+

+ +
+
+ +
+ + + +
+
+

Properties

+
+ +
+ +
+
+ +
+

$_proxyVars

+
$_proxyVars : boolean
+

+ + +

Type

+ boolean + — Control if the `Forwarded-For-*` headers are used
+
+ +
+ +
+
+ +
+

$_host

+
$_host : string|null
+

+ + +

Type

+ string|null +
+
+ +
+ +
+
+ +
+

$_protocol

+
$_protocol : string|null
+

+ + +

Type

+ string|null +
+
+ +
+ +
+
+ +
+

$_port

+
$_port : integer|null
+

+ + +

Type

+ integer|null +
+
+ +
+ +
+
+ +
+

$_baseurlpath

+
$_baseurlpath : string|null
+

+ + +

Type

+ string|null +
+
+ +
+ +
+
+ +
+

$_protocolRegex

+
$_protocolRegex : string
+

+ + +

Type

+ string +
+
+ +
+ + + +
+

Methods

+ +
+ +
+
+ +
+

t()

+ +
t(string  $msg, array|null  $args = array()) : string
+

Translates any string. Accepts args

+ + +

Parameters

+ + + + + + + + + + + +
string$msg

Message to be translated

array|null$args

Arguments

+ + +

Returns

+ string + —

$translatedMsg Translated text

+ +
+
+ +
+ +
+
+ +
+

loadXML()

+ +
loadXML(\DOMDocument  $dom, string  $xml) : \DOMDocument|false
+

This function load an XML string in a save way.

+

Prevent XEE/XXE Attacks

+ +

Parameters

+ + + + + + + + + + + +
\DOMDocument$dom

The document where load the xml.

string$xml

The XML string to be loaded.

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ \DOMDocument|false + —

$dom The result of load the XML at the DomDocument

+ +
+
+ +
+ +
+
+ +
+

validateXML()

+ +
validateXML(string|\DOMDocument  $xml, string  $schema, boolean  $debug = false, string  $schemaPath = null) : string|\DOMDocument
+

This function attempts to validate an XML string against the specified schema.

+

It will parse the string into a DOM document and validate this document against the schema.

+ +

Parameters

+ + + + + + + + + + + + + + + + + + + + + +
string|\DOMDocument$xml

The XML string or document which should be validated.

string$schema

The schema filename which should be used.

boolean$debug

To disable/enable the debug mode

string$schemaPath

Change schema path

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ string|\DOMDocument + —

$dom string that explains the problem or the DOMDocument

+ +
+
+ +
+ +
+
+ +
+

treeCopyReplace()

+ +
treeCopyReplace(\DomNode  $targetNode, \DomNode  $sourceNode, boolean  $recurse = false) : \DOMNode
+

Import a node tree into a target document +Copy it before a reference node as a sibling +and at the end of the copy remove +the reference node in the target document +As it were 'replacing' it +Leaving nested default namespaces alone +(Standard importNode with deep copy + mangles nested default namespaces)

+

The reference node must not be a DomDocument +It CAN be the top element of a document +Returns the copied node in the target document

+ +

Parameters

+ + + + + + + + + + + + + + + + +
\DomNode$targetNode
\DomNode$sourceNode
boolean$recurse
+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ \DOMNode + +
+
+ +
+ +
+
+ +
+

formatCert()

+ +
formatCert(string  $cert, boolean  $heads = true) : string
+

Returns a x509 cert (adding header & footer if required).

+ + +

Parameters

+ + + + + + + + + + + +
string$cert

A x509 unformated cert

boolean$heads

True if we want to include head and footer

+ + +

Returns

+ string + —

$x509 Formatted cert

+ +
+
+ +
+ +
+
+ +
+

formatPrivateKey()

+ +
formatPrivateKey(string  $key, boolean  $heads = true) : string
+

Returns a private key (adding header & footer if required).

+ + +

Parameters

+ + + + + + + + + + + +
string$key

A private key

boolean$heads

True if we want to include head and footer

+ + +

Returns

+ string + —

$rsaKey Formatted private key

+ +
+
+ +
+ +
+
+ +
+

getStringBetween()

+ +
getStringBetween(string  $str, string  $start, string  $end) : string
+

Extracts a substring between 2 marks

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$str

The target string

string$start

The initial mark

string$end

The end mark

+ + +

Returns

+ string + —

A substring or an empty string if is not able to find the marks +or if there is no string between the marks

+ +
+
+ +
+ +
+
+ +
+

redirect()

+ +
redirect(string  $url, array  $parameters = array(), boolean  $stay = false) : string|null
+

Executes a redirection to the provided url (or return the target url).

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$url

The target url

array$parameters

Extra parameters to be passed as part of the url

boolean$stay

True if we want to stay (returns the url string) False to redirect

+ +

Throws

+
+
\OneLogin_Saml2_Error
+
+
+ +

Returns

+ string|null + —

$url

+ +
+
+ +
+ +
+
+ +
+

setProtocolRegex()

+ +
setProtocolRegex(  $protocolRegex) 
+

+ + +

Parameters

+ + + + + + +
$protocolRegex
+ + + +
+
+ +
+ +
+
+ +
+

setBaseURL()

+ +
setBaseURL(  $baseurl) 
+

+ + +

Parameters

+ + + + + + +
$baseurl

string The base url to be used when constructing URLs

+ + + +
+
+ +
+ +
+
+ +
+

setProxyVars()

+ +
setProxyVars(  $proxyVars) 
+

+ + +

Parameters

+ + + + + + +
$proxyVars

bool Whether to use X-Forwarded-* headers to determine port/domain/protocol

+ + + +
+
+ +
+ +
+
+ +
+

getProxyVars()

+ +
getProxyVars() 
+

return bool

+ + + + + +
+
+ +
+ +
+
+ +
+

getSelfURLhost()

+ +
getSelfURLhost() : string
+

Returns the protocol + the current host + the port (if different than +common ports).

+ + + + +

Returns

+ string + —

$url

+ +
+
+ +
+ +
+
+ +
+

setSelfHost()

+ +
setSelfHost(  $host) 
+

+ + +

Parameters

+ + + + + + +
$host

string The host to use when constructing URLs

+ + + +
+
+ +
+ +
+
+ +
+

setBaseURLPath()

+ +
setBaseURLPath(  $baseurlpath) 
+

+ + +

Parameters

+ + + + + + +
$baseurlpath

string The baseurl path to use when constructing URLs

+ + + +
+
+ +
+ +
+
+ +
+

getBaseURLPath()

+ +
getBaseURLPath() : string
+

+ + + + +

Returns

+ string + —

The baseurlpath to be used when constructing URLs

+ +
+
+ +
+ +
+
+ +
+

setSelfPort()

+ +
setSelfPort(  $port) 
+

+ + +

Parameters

+ + + + + + +
$port

int The port number to use when constructing URLs

+ + + +
+
+ +
+ +
+
+ +
+

setSelfProtocol()

+ +
setSelfProtocol(  $protocol) 
+

+ + +

Parameters

+ + + + + + +
$protocol

string The protocol to identify as using, usually http or https

+ + + +
+
+ +
+ +
+
+ +
+

getSelfProtocol()

+ +
getSelfProtocol() : string
+

+ + + + +

Returns

+ string + —

http|https

+ +
+
+ +
+ +
+
+ +
+

getSelfHost()

+ +
getSelfHost() : string
+

Returns the current host.

+ + + + +

Returns

+ string + —

$currentHost The current host

+ +
+
+ +
+ +
+
+ +
+

getSelfPort()

+ +
getSelfPort() : null|string
+

+ + + + +

Returns

+ null|string + —

The port number used for the request

+ +
+
+ +
+ +
+
+ +
+

isHTTPS()

+ +
isHTTPS() : boolean
+

Checks if https or http.

+ + + + +

Returns

+ boolean + —

$isHttps False if https is not active

+ +
+
+ +
+ +
+
+ +
+

getSelfURLNoQuery()

+ +
getSelfURLNoQuery() : string
+

Returns the URL of the current host + current view.

+ + + + +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

getSelfRoutedURLNoQuery()

+ +
getSelfRoutedURLNoQuery() : string
+

Returns the routed URL of the current host + current view.

+ + + + +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

strLreplace()

+ +
strLreplace(  $search,   $replace,   $subject) 
+

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
$search
$replace
$subject
+ + + +
+
+ +
+ +
+
+ +
+

getSelfURL()

+ +
getSelfURL() : string
+

Returns the URL of the current host + current view + query.

+ + + + +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

extractOriginalQueryParam()

+ +
extractOriginalQueryParam(string  $name) : string
+

Extract a query param - as it was sent - from $_SERVER[QUERY_STRING]

+ + +

Parameters

+ + + + + + +
string$name

The param to-be extracted

+ + +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

generateUniqueID()

+ +
generateUniqueID() : string
+

Generates an unique string (used for example as ID for assertions).

+ + + + +

Returns

+ string + —

A unique string

+ +
+
+ +
+ +
+
+ +
+

parseTime2SAML()

+ +
parseTime2SAML(string|integer  $time) : string
+

Converts a UNIX timestamp to SAML2 timestamp on the form +yyyy-mm-ddThh:mm:ss(\.s+)?Z.

+ + +

Parameters

+ + + + + + +
string|integer$time

The time we should convert (DateTime).

+ + +

Returns

+ string + —

$timestamp SAML2 timestamp.

+ +
+
+ +
+ +
+
+ +
+

parseSAML2Time()

+ +
parseSAML2Time(string  $time) : integer
+

Converts a SAML2 timestamp on the form yyyy-mm-ddThh:mm:ss(\.s+)?Z +to a UNIX timestamp. The sub-second part is ignored.

+ + +

Parameters

+ + + + + + +
string$time

The time we should convert (SAML Timestamp).

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ integer + —

$timestamp Converted to a unix timestamp.

+ +
+
+ +
+ +
+
+ +
+

parseDuration()

+ +
parseDuration(string  $duration, integer|null  $timestamp = null) : integer
+

Interprets a ISO8601 duration value relative to a given timestamp.

+ + +

Parameters

+ + + + + + + + + + + +
string$duration

The duration, as a string.

integer|null$timestamp

The unix timestamp we should apply the +duration to. Optional, default to the +current time.

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ integer + —

The new timestamp, after the duration is applied.

+ +
+
+ +
+ +
+
+ +
+

getExpireTime()

+ +
getExpireTime(string|null  $cacheDuration = null, string|integer|null  $validUntil = null) : integer|null
+

Compares 2 dates and returns the earliest.

+ + +

Parameters

+ + + + + + + + + + + +
string|null$cacheDuration

The duration, as a string.

string|integer|null$validUntil

The valid until date, as a string or as a timestamp

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ integer|null + —

$expireTime The expiration time.

+ +
+
+ +
+ +
+
+ +
+

query()

+ +
query(\DOMDocument  $dom, string  $query, \DomElement|null  $context = null) : \DOMNodeList
+

Extracts nodes from the DOMDocument.

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
\DOMDocument$dom

The DOMDocument

string$query

Xpath Expresion

\DomElement|null$context

Context Node (DomElement)

+ + +

Returns

+ \DOMNodeList + —

The queried nodes

+ +
+
+ +
+ +
+
+ +
+

isSessionStarted()

+ +
isSessionStarted() : boolean
+

Checks if the session is started or not.

+ + + + +

Returns

+ boolean + —

true if the sessíon is started

+ +
+
+ +
+ +
+
+ +
+

deleteLocalSession()

+ +
deleteLocalSession() 
+

Deletes the local session.

+ + + + + +
+
+ +
+ +
+
+ +
+

calculateX509Fingerprint()

+ +
calculateX509Fingerprint(string  $x509cert, string  $alg = 'sha1') : null|string
+

Calculates the fingerprint of a x509cert.

+ + +

Parameters

+ + + + + + + + + + + +
string$x509cert

x509 cert

string$alg
+ + +

Returns

+ null|string + —

Formatted fingerprint

+ +
+
+ +
+ +
+
+ +
+

formatFingerPrint()

+ +
formatFingerPrint(string  $fingerprint) : string
+

Formates a fingerprint.

+ + +

Parameters

+ + + + + + +
string$fingerprint

fingerprint

+ + +

Returns

+ string + —

Formatted fingerprint

+ +
+
+ +
+ +
+
+ +
+

generateNameId()

+ +
generateNameId(string  $value, string  $spnq, string|null  $format = null, string|null  $cert = null, string|null  $nq = null) : string
+

Generates a nameID.

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
string$value

fingerprint

string$spnq

SP Name Qualifier

string|null$format

SP Format

string|null$cert

IdP Public cert to encrypt the nameID

string|null$nq

IdP Name Qualifier

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ string + —

$nameIDElement DOMElement | XMLSec nameID

+ +
+
+ +
+ +
+
+ +
+

getStatus()

+ +
getStatus(\DOMDocument  $dom) : array
+

Gets Status from a Response.

+ + +

Parameters

+ + + + + + +
\DOMDocument$dom

The Response as XML

+ +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ array + —

$status The Status, an array with the code and a message.

+ +
+
+ +
+ +
+
+ +
+

decryptElement()

+ +
decryptElement(\DOMElement  $encryptedData, \XMLSecurityKey  $inputKey, boolean  $formatOutput = true) : \DOMElement
+

Decrypts an encrypted element.

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
\DOMElement$encryptedData

The encrypted data.

\XMLSecurityKey$inputKey

The decryption key.

boolean$formatOutput

Format or not the output.

+ +

Throws

+
+
\OneLogin_Saml2_ValidationError
+
+
+ +

Returns

+ \DOMElement + —

The decrypted element.

+ +
+
+ +
+ +
+
+ +
+

castKey()

+ +
castKey(\XMLSecurityKey  $key, string  $algorithm, string  $type = 'public') : \XMLSecurityKey
+

Converts a XMLSecurityKey to the correct algorithm.

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
\XMLSecurityKey$key

The key.

string$algorithm

The desired algorithm.

string$type

Public or private key, defaults to public.

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ \XMLSecurityKey + —

The new key.

+ +
+
+ +
+ +
+
+ +
+

isSupportedSigningAlgorithm()

+ +
isSupportedSigningAlgorithm(  $algorithm) : boolean
+

+ + +

Parameters

+ + + + + + +
$algorithm
+ + +

Returns

+ boolean + +
+
+ +
+ +
+
+ +
+

addSign()

+ +
addSign(string|\DomDocument  $xml, string  $key, string  $cert, string  $signAlgorithm = \XMLSecurityKey::RSA_SHA1, string  $digestAlgorithm = \XMLSecurityDSig::SHA1) : string
+

Adds signature key and senders certificate to an element (Message or Assertion).

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + +
string|\DomDocument$xml

The element we should sign

string$key

The private key

string$cert

The public

string$signAlgorithm

Signature algorithm method

string$digestAlgorithm

Digest algorithm method

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ string + +
+
+ +
+ +
+
+ +
+

validateSign()

+ +
validateSign(string|\DomNode  $xml, string|null  $cert = null, string|null  $fingerprint = null, string|null  $fingerprintalg = 'sha1', string|null  $xpath = null, array|null  $multiCerts = null) : boolean
+

Validates a signature (Message or Assertion).

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
string|\DomNode$xml

The element we should validate

string|null$cert

The public cert

string|null$fingerprint

The fingerprint of the public cert

string|null$fingerprintalg

The algorithm used to get the fingerprint

string|null$xpath

The xpath of the signed element

array|null$multiCerts

Multiple public certs

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ boolean + +
+
+ +
+ +
+
+ +
+

validateBinarySign()

+ +
validateBinarySign(string  $messageType, array  $getData, array  $idpData, boolean  $retrieveParametersFromServer = false) : boolean
+

Validates a binary signature

+ + +

Parameters

+ + + + + + + + + + + + + + + + + + + + + +
string$messageType

Type of SAML Message

array$getData

HTTP GET array

array$idpData

IdP setting data

boolean$retrieveParametersFromServer

Indicates where to get the values in order to validate the Sign, from getData or from $_SERVER

+ +

Throws

+
+
\Exception
+
+
+ +

Returns

+ boolean + +
+
+ +
+ +
+
+ +
+

getRawHost()

+ +
getRawHost() : string
+

+ + + + +

Returns

+ string + —

The raw host name

+ +
+
+ +
+ +
+
+ +
+

buildWithBaseURLPath()

+ +
buildWithBaseURLPath(  $info) : string
+

Returns the part of the URL with the BaseURLPath.

+ + +

Parameters

+ + + + + + +
$info
+ + +

Returns

+ string + +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/classes/OneLogin_Saml2_ValidationError.html b/docs/Saml2/classes/OneLogin_Saml2_ValidationError.html new file mode 100644 index 00000000..907e9f05 --- /dev/null +++ b/docs/Saml2/classes/OneLogin_Saml2_ValidationError.html @@ -0,0 +1,1451 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

\OneLogin_Saml2_ValidationError

+

This class implements another custom Exception handler, +related to exceptions that happens during validation process.

+ + + +
+

Summary

+
+
+ Methods +
+
+ Properties +
+
+ Constants +
+
+
+
+ __construct()
+
+
+ No public properties found +
+
+ UNSUPPORTED_SAML_VERSION
+ MISSING_ID
+ WRONG_NUMBER_OF_ASSERTIONS
+ MISSING_STATUS
+ MISSING_STATUS_CODE
+ STATUS_CODE_IS_NOT_SUCCESS
+ WRONG_SIGNED_ELEMENT
+ ID_NOT_FOUND_IN_SIGNED_ELEMENT
+ DUPLICATED_ID_IN_SIGNED_ELEMENTS
+ INVALID_SIGNED_ELEMENT
+ DUPLICATED_REFERENCE_IN_SIGNED_ELEMENTS
+ UNEXPECTED_SIGNED_ELEMENTS
+ WRONG_NUMBER_OF_SIGNATURES_IN_RESPONSE
+ WRONG_NUMBER_OF_SIGNATURES_IN_ASSERTION
+ INVALID_XML_FORMAT
+ WRONG_INRESPONSETO
+ NO_ENCRYPTED_ASSERTION
+ NO_ENCRYPTED_NAMEID
+ MISSING_CONDITIONS
+ ASSERTION_TOO_EARLY
+ ASSERTION_EXPIRED
+ WRONG_NUMBER_OF_AUTHSTATEMENTS
+ NO_ATTRIBUTESTATEMENT
+ ENCRYPTED_ATTRIBUTES
+ WRONG_DESTINATION
+ EMPTY_DESTINATION
+ WRONG_AUDIENCE
+ ISSUER_MULTIPLE_IN_RESPONSE
+ ISSUER_NOT_FOUND_IN_ASSERTION
+ WRONG_ISSUER
+ SESSION_EXPIRED
+ WRONG_SUBJECTCONFIRMATION
+ NO_SIGNED_MESSAGE
+ NO_SIGNED_ASSERTION
+ NO_SIGNATURE_FOUND
+ KEYINFO_NOT_FOUND_IN_ENCRYPTED_DATA
+ CHILDREN_NODE_NOT_FOUND_IN_KEYINFO
+ UNSUPPORTED_RETRIEVAL_METHOD
+ NO_NAMEID
+ EMPTY_NAMEID
+ SP_NAME_QUALIFIER_NAME_MISMATCH
+ DUPLICATED_ATTRIBUTE_NAME_FOUND
+ INVALID_SIGNATURE
+ WRONG_NUMBER_OF_SIGNATURES
+ RESPONSE_EXPIRED
+ UNEXPECTED_REFERENCE
+ NOT_SUPPORTED
+ KEY_ALGORITHM_ERROR
+ MISSING_ENCRYPTED_ELEMENT
+
+
+
+
+ No protected methods found +
+
+ No protected properties found +
+
+ N/A +
+
+
+
+ No private methods found +
+
+ No private properties found +
+
+ N/A +
+
+
+
+ +
+ + +
+
+

Constants

+
+ +
+ +
+
+ +
+

UNSUPPORTED_SAML_VERSION

+
UNSUPPORTED_SAML_VERSION
+

+ +
+
+ +
+ +
+
+ +
+

MISSING_ID

+
MISSING_ID
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_NUMBER_OF_ASSERTIONS

+
WRONG_NUMBER_OF_ASSERTIONS
+

+ +
+
+ +
+ +
+
+ +
+

MISSING_STATUS

+
MISSING_STATUS
+

+ +
+
+ +
+ +
+
+ +
+

MISSING_STATUS_CODE

+
MISSING_STATUS_CODE
+

+ +
+
+ +
+ +
+
+ +
+

STATUS_CODE_IS_NOT_SUCCESS

+
STATUS_CODE_IS_NOT_SUCCESS
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_SIGNED_ELEMENT

+
WRONG_SIGNED_ELEMENT
+

+ +
+
+ +
+ +
+
+ +
+

ID_NOT_FOUND_IN_SIGNED_ELEMENT

+
ID_NOT_FOUND_IN_SIGNED_ELEMENT
+

+ +
+
+ +
+ +
+
+ +
+

DUPLICATED_ID_IN_SIGNED_ELEMENTS

+
DUPLICATED_ID_IN_SIGNED_ELEMENTS
+

+ +
+
+ +
+ +
+
+ +
+

INVALID_SIGNED_ELEMENT

+
INVALID_SIGNED_ELEMENT
+

+ +
+
+ +
+ +
+
+ +
+

DUPLICATED_REFERENCE_IN_SIGNED_ELEMENTS

+
DUPLICATED_REFERENCE_IN_SIGNED_ELEMENTS
+

+ +
+
+ +
+ +
+
+ +
+

UNEXPECTED_SIGNED_ELEMENTS

+
UNEXPECTED_SIGNED_ELEMENTS
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_NUMBER_OF_SIGNATURES_IN_RESPONSE

+
WRONG_NUMBER_OF_SIGNATURES_IN_RESPONSE
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_NUMBER_OF_SIGNATURES_IN_ASSERTION

+
WRONG_NUMBER_OF_SIGNATURES_IN_ASSERTION
+

+ +
+
+ +
+ +
+
+ +
+

INVALID_XML_FORMAT

+
INVALID_XML_FORMAT
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_INRESPONSETO

+
WRONG_INRESPONSETO
+

+ +
+
+ +
+ +
+
+ +
+

NO_ENCRYPTED_ASSERTION

+
NO_ENCRYPTED_ASSERTION
+

+ +
+
+ +
+ +
+
+ +
+

NO_ENCRYPTED_NAMEID

+
NO_ENCRYPTED_NAMEID
+

+ +
+
+ +
+ +
+
+ +
+

MISSING_CONDITIONS

+
MISSING_CONDITIONS
+

+ +
+
+ +
+ +
+
+ +
+

ASSERTION_TOO_EARLY

+
ASSERTION_TOO_EARLY
+

+ +
+
+ +
+ +
+
+ +
+

ASSERTION_EXPIRED

+
ASSERTION_EXPIRED
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_NUMBER_OF_AUTHSTATEMENTS

+
WRONG_NUMBER_OF_AUTHSTATEMENTS
+

+ +
+
+ +
+ +
+
+ +
+

NO_ATTRIBUTESTATEMENT

+
NO_ATTRIBUTESTATEMENT
+

+ +
+
+ +
+ +
+
+ +
+

ENCRYPTED_ATTRIBUTES

+
ENCRYPTED_ATTRIBUTES
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_DESTINATION

+
WRONG_DESTINATION
+

+ +
+
+ +
+ +
+
+ +
+

EMPTY_DESTINATION

+
EMPTY_DESTINATION
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_AUDIENCE

+
WRONG_AUDIENCE
+

+ +
+
+ +
+ +
+
+ +
+

ISSUER_MULTIPLE_IN_RESPONSE

+
ISSUER_MULTIPLE_IN_RESPONSE
+

+ +
+
+ +
+ +
+
+ +
+

ISSUER_NOT_FOUND_IN_ASSERTION

+
ISSUER_NOT_FOUND_IN_ASSERTION
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_ISSUER

+
WRONG_ISSUER
+

+ +
+
+ +
+ +
+
+ +
+

SESSION_EXPIRED

+
SESSION_EXPIRED
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_SUBJECTCONFIRMATION

+
WRONG_SUBJECTCONFIRMATION
+

+ +
+
+ +
+ +
+
+ +
+

NO_SIGNED_MESSAGE

+
NO_SIGNED_MESSAGE
+

+ +
+
+ +
+ +
+
+ +
+

NO_SIGNED_ASSERTION

+
NO_SIGNED_ASSERTION
+

+ +
+
+ +
+ +
+
+ +
+

NO_SIGNATURE_FOUND

+
NO_SIGNATURE_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

KEYINFO_NOT_FOUND_IN_ENCRYPTED_DATA

+
KEYINFO_NOT_FOUND_IN_ENCRYPTED_DATA
+

+ +
+
+ +
+ +
+
+ +
+

CHILDREN_NODE_NOT_FOUND_IN_KEYINFO

+
CHILDREN_NODE_NOT_FOUND_IN_KEYINFO
+

+ +
+
+ +
+ +
+
+ +
+

UNSUPPORTED_RETRIEVAL_METHOD

+
UNSUPPORTED_RETRIEVAL_METHOD
+

+ +
+
+ +
+ +
+
+ +
+

NO_NAMEID

+
NO_NAMEID
+

+ +
+
+ +
+ +
+
+ +
+

EMPTY_NAMEID

+
EMPTY_NAMEID
+

+ +
+
+ +
+ +
+
+ +
+

SP_NAME_QUALIFIER_NAME_MISMATCH

+
SP_NAME_QUALIFIER_NAME_MISMATCH
+

+ +
+
+ +
+ +
+
+ +
+

DUPLICATED_ATTRIBUTE_NAME_FOUND

+
DUPLICATED_ATTRIBUTE_NAME_FOUND
+

+ +
+
+ +
+ +
+
+ +
+

INVALID_SIGNATURE

+
INVALID_SIGNATURE
+

+ +
+
+ +
+ +
+
+ +
+

WRONG_NUMBER_OF_SIGNATURES

+
WRONG_NUMBER_OF_SIGNATURES
+

+ +
+
+ +
+ +
+
+ +
+

RESPONSE_EXPIRED

+
RESPONSE_EXPIRED
+

+ +
+
+ +
+ +
+
+ +
+

UNEXPECTED_REFERENCE

+
UNEXPECTED_REFERENCE
+

+ +
+
+ +
+ +
+
+ +
+

NOT_SUPPORTED

+
NOT_SUPPORTED
+

+ +
+
+ +
+ +
+
+ +
+

KEY_ALGORITHM_ERROR

+
KEY_ALGORITHM_ERROR
+

+ +
+
+ +
+ +
+
+ +
+

MISSING_ENCRYPTED_ELEMENT

+
MISSING_ENCRYPTED_ELEMENT
+

+ +
+
+ +
+ + + + +
+

Methods

+ +
+ +
+
+ +
+

__construct()

+ +
__construct(string  $msg, integer  $code, array|null  $args = null) 
+

Constructor

+ + +

Parameters

+ + + + + + + + + + + + + + + + +
string$msg

Describes the error.

integer$code

The code error (defined in the error class).

array|null$args

Arguments used in the message that describes the error.

+ + + +
+
+ +
+ +
+
+ + + + +
+ + + diff --git a/docs/Saml2/css/bootstrap-combined.no-icons.min.css b/docs/Saml2/css/bootstrap-combined.no-icons.min.css new file mode 100644 index 00000000..5ab243ec --- /dev/null +++ b/docs/Saml2/css/bootstrap-combined.no-icons.min.css @@ -0,0 +1,732 @@ +/*! + * Bootstrap v2.3.2 + * + * Copyright 2012 Twitter, Inc + * Licensed under the Apache License v2.0 + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Designed and built with all the love in the world @twitter by @mdo and @fat. + */ +.clearfix{*zoom:1;}.clearfix:before,.clearfix:after{display:table;content:"";line-height:0;} +.clearfix:after{clear:both;} +.hide-text{font:0/0 a;color:transparent;text-shadow:none;background-color:transparent;border:0;} +.input-block-level{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} +article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;} +audio,canvas,video{display:inline-block;*display:inline;*zoom:1;} +audio:not([controls]){display:none;} +html{font-size:100%;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;} +a:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +a:hover,a:active{outline:0;} +sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline;} +sup{top:-0.5em;} +sub{bottom:-0.25em;} +img{max-width:100%;width:auto\9;height:auto;vertical-align:middle;border:0;-ms-interpolation-mode:bicubic;} +#map_canvas img,.google-maps img{max-width:none;} +button,input,select,textarea{margin:0;font-size:100%;vertical-align:middle;} +button,input{*overflow:visible;line-height:normal;} +button::-moz-focus-inner,input::-moz-focus-inner{padding:0;border:0;} +button,html input[type="button"],input[type="reset"],input[type="submit"]{-webkit-appearance:button;cursor:pointer;} +label,select,button,input[type="button"],input[type="reset"],input[type="submit"],input[type="radio"],input[type="checkbox"]{cursor:pointer;} +input[type="search"]{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;-webkit-appearance:textfield;} +input[type="search"]::-webkit-search-decoration,input[type="search"]::-webkit-search-cancel-button{-webkit-appearance:none;} +textarea{overflow:auto;vertical-align:top;} +@media print{*{text-shadow:none !important;color:#000 !important;background:transparent !important;box-shadow:none !important;} a,a:visited{text-decoration:underline;} a[href]:after{content:" (" attr(href) ")";} abbr[title]:after{content:" (" attr(title) ")";} .ir a:after,a[href^="javascript:"]:after,a[href^="#"]:after{content:"";} pre,blockquote{border:1px solid #999;page-break-inside:avoid;} thead{display:table-header-group;} tr,img{page-break-inside:avoid;} img{max-width:100% !important;} @page {margin:0.5cm;}p,h2,h3{orphans:3;widows:3;} h2,h3{page-break-after:avoid;}}body{margin:0;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:14px;line-height:20px;color:#333333;background-color:#ffffff;} +a{color:#0088cc;text-decoration:none;} +a:hover,a:focus{color:#005580;text-decoration:underline;} +.img-rounded{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.img-polaroid{padding:4px;background-color:#fff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);box-shadow:0 1px 3px rgba(0, 0, 0, 0.1);} +.img-circle{-webkit-border-radius:500px;-moz-border-radius:500px;border-radius:500px;} +.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} +.row:after{clear:both;} +[class*="span"]{float:left;min-height:1px;margin-left:20px;} +.container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.span12{width:940px;} +.span11{width:860px;} +.span10{width:780px;} +.span9{width:700px;} +.span8{width:620px;} +.span7{width:540px;} +.span6{width:460px;} +.span5{width:380px;} +.span4{width:300px;} +.span3{width:220px;} +.span2{width:140px;} +.span1{width:60px;} +.offset12{margin-left:980px;} +.offset11{margin-left:900px;} +.offset10{margin-left:820px;} +.offset9{margin-left:740px;} +.offset8{margin-left:660px;} +.offset7{margin-left:580px;} +.offset6{margin-left:500px;} +.offset5{margin-left:420px;} +.offset4{margin-left:340px;} +.offset3{margin-left:260px;} +.offset2{margin-left:180px;} +.offset1{margin-left:100px;} +.row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} +.row-fluid:after{clear:both;} +.row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.127659574468085%;*margin-left:2.074468085106383%;} +.row-fluid [class*="span"]:first-child{margin-left:0;} +.row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.127659574468085%;} +.row-fluid .span12{width:100%;*width:99.94680851063829%;} +.row-fluid .span11{width:91.48936170212765%;*width:91.43617021276594%;} +.row-fluid .span10{width:82.97872340425532%;*width:82.92553191489361%;} +.row-fluid .span9{width:74.46808510638297%;*width:74.41489361702126%;} +.row-fluid .span8{width:65.95744680851064%;*width:65.90425531914893%;} +.row-fluid .span7{width:57.44680851063829%;*width:57.39361702127659%;} +.row-fluid .span6{width:48.93617021276595%;*width:48.88297872340425%;} +.row-fluid .span5{width:40.42553191489362%;*width:40.37234042553192%;} +.row-fluid .span4{width:31.914893617021278%;*width:31.861702127659576%;} +.row-fluid .span3{width:23.404255319148934%;*width:23.351063829787233%;} +.row-fluid .span2{width:14.893617021276595%;*width:14.840425531914894%;} +.row-fluid .span1{width:6.382978723404255%;*width:6.329787234042553%;} +.row-fluid .offset12{margin-left:104.25531914893617%;*margin-left:104.14893617021275%;} +.row-fluid .offset12:first-child{margin-left:102.12765957446808%;*margin-left:102.02127659574467%;} +.row-fluid .offset11{margin-left:95.74468085106382%;*margin-left:95.6382978723404%;} +.row-fluid .offset11:first-child{margin-left:93.61702127659574%;*margin-left:93.51063829787232%;} +.row-fluid .offset10{margin-left:87.23404255319149%;*margin-left:87.12765957446807%;} +.row-fluid .offset10:first-child{margin-left:85.1063829787234%;*margin-left:84.99999999999999%;} +.row-fluid .offset9{margin-left:78.72340425531914%;*margin-left:78.61702127659572%;} +.row-fluid .offset9:first-child{margin-left:76.59574468085106%;*margin-left:76.48936170212764%;} +.row-fluid .offset8{margin-left:70.2127659574468%;*margin-left:70.10638297872339%;} +.row-fluid .offset8:first-child{margin-left:68.08510638297872%;*margin-left:67.9787234042553%;} +.row-fluid .offset7{margin-left:61.70212765957446%;*margin-left:61.59574468085106%;} +.row-fluid .offset7:first-child{margin-left:59.574468085106375%;*margin-left:59.46808510638297%;} +.row-fluid .offset6{margin-left:53.191489361702125%;*margin-left:53.085106382978715%;} +.row-fluid .offset6:first-child{margin-left:51.063829787234035%;*margin-left:50.95744680851063%;} +.row-fluid .offset5{margin-left:44.68085106382979%;*margin-left:44.57446808510638%;} +.row-fluid .offset5:first-child{margin-left:42.5531914893617%;*margin-left:42.4468085106383%;} +.row-fluid .offset4{margin-left:36.170212765957444%;*margin-left:36.06382978723405%;} +.row-fluid .offset4:first-child{margin-left:34.04255319148936%;*margin-left:33.93617021276596%;} +.row-fluid .offset3{margin-left:27.659574468085104%;*margin-left:27.5531914893617%;} +.row-fluid .offset3:first-child{margin-left:25.53191489361702%;*margin-left:25.425531914893618%;} +.row-fluid .offset2{margin-left:19.148936170212764%;*margin-left:19.04255319148936%;} +.row-fluid .offset2:first-child{margin-left:17.02127659574468%;*margin-left:16.914893617021278%;} +.row-fluid .offset1{margin-left:10.638297872340425%;*margin-left:10.53191489361702%;} +.row-fluid .offset1:first-child{margin-left:8.51063829787234%;*margin-left:8.404255319148938%;} +[class*="span"].hide,.row-fluid [class*="span"].hide{display:none;} +[class*="span"].pull-right,.row-fluid [class*="span"].pull-right{float:right;} +.container{margin-right:auto;margin-left:auto;*zoom:1;}.container:before,.container:after{display:table;content:"";line-height:0;} +.container:after{clear:both;} +.container-fluid{padding-right:20px;padding-left:20px;*zoom:1;}.container-fluid:before,.container-fluid:after{display:table;content:"";line-height:0;} +.container-fluid:after{clear:both;} +p{margin:0 0 10px;} +.lead{margin-bottom:20px;font-size:21px;font-weight:200;line-height:30px;} +small{font-size:85%;} +strong{font-weight:bold;} +em{font-style:italic;} +cite{font-style:normal;} +.muted{color:#999999;} +a.muted:hover,a.muted:focus{color:#808080;} +.text-warning{color:#c09853;} +a.text-warning:hover,a.text-warning:focus{color:#a47e3c;} +.text-error{color:#b94a48;} +a.text-error:hover,a.text-error:focus{color:#953b39;} +.text-info{color:#3a87ad;} +a.text-info:hover,a.text-info:focus{color:#2d6987;} +.text-success{color:#468847;} +a.text-success:hover,a.text-success:focus{color:#356635;} +.text-left{text-align:left;} +.text-right{text-align:right;} +.text-center{text-align:center;} +h1,h2,h3,h4,h5,h6{margin:10px 0;font-family:inherit;font-weight:bold;line-height:20px;color:inherit;text-rendering:optimizelegibility;}h1 small,h2 small,h3 small,h4 small,h5 small,h6 small{font-weight:normal;line-height:1;color:#999999;} +h1,h2,h3{line-height:40px;} +h1{font-size:38.5px;} +h2{font-size:31.5px;} +h3{font-size:24.5px;} +h4{font-size:17.5px;} +h5{font-size:14px;} +h6{font-size:11.9px;} +h1 small{font-size:24.5px;} +h2 small{font-size:17.5px;} +h3 small{font-size:14px;} +h4 small{font-size:14px;} +.page-header{padding-bottom:9px;margin:20px 0 30px;border-bottom:1px solid #eeeeee;} +ul,ol{padding:0;margin:0 0 10px 25px;} +ul ul,ul ol,ol ol,ol ul{margin-bottom:0;} +li{line-height:20px;} +ul.unstyled,ol.unstyled{margin-left:0;list-style:none;} +ul.inline,ol.inline{margin-left:0;list-style:none;}ul.inline>li,ol.inline>li{display:inline-block;*display:inline;*zoom:1;padding-left:5px;padding-right:5px;} +dl{margin-bottom:20px;} +dt,dd{line-height:20px;} +dt{font-weight:bold;} +dd{margin-left:10px;} +.dl-horizontal{*zoom:1;}.dl-horizontal:before,.dl-horizontal:after{display:table;content:"";line-height:0;} +.dl-horizontal:after{clear:both;} +.dl-horizontal dt{float:left;width:160px;clear:left;text-align:right;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;} +.dl-horizontal dd{margin-left:180px;} +hr{margin:20px 0;border:0;border-top:1px solid #eeeeee;border-bottom:1px solid #ffffff;} +abbr[title],abbr[data-original-title]{cursor:help;border-bottom:1px dotted #999999;} +abbr.initialism{font-size:90%;text-transform:uppercase;} +blockquote{padding:0 0 0 15px;margin:0 0 20px;border-left:5px solid #eeeeee;}blockquote p{margin-bottom:0;font-size:17.5px;font-weight:300;line-height:1.25;} +blockquote small{display:block;line-height:20px;color:#999999;}blockquote small:before{content:'\2014 \00A0';} +blockquote.pull-right{float:right;padding-right:15px;padding-left:0;border-right:5px solid #eeeeee;border-left:0;}blockquote.pull-right p,blockquote.pull-right small{text-align:right;} +blockquote.pull-right small:before{content:'';} +blockquote.pull-right small:after{content:'\00A0 \2014';} +q:before,q:after,blockquote:before,blockquote:after{content:"";} +address{display:block;margin-bottom:20px;font-style:normal;line-height:20px;} +code,pre{padding:0 3px 2px;font-family:Monaco,Menlo,Consolas,"Courier New",monospace;font-size:12px;color:#333333;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +code{padding:2px 4px;color:#d14;background-color:#f7f7f9;border:1px solid #e1e1e8;white-space:nowrap;} +pre{display:block;padding:9.5px;margin:0 0 10px;font-size:13px;line-height:20px;word-break:break-all;word-wrap:break-word;white-space:pre;white-space:pre-wrap;background-color:#f5f5f5;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.15);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}pre.prettyprint{margin-bottom:20px;} +pre code{padding:0;color:inherit;white-space:pre;white-space:pre-wrap;background-color:transparent;border:0;} +.pre-scrollable{max-height:340px;overflow-y:scroll;} +.label,.badge{display:inline-block;padding:2px 4px;font-size:11.844px;font-weight:bold;line-height:14px;color:#ffffff;vertical-align:baseline;white-space:nowrap;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#999999;} +.label{-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.badge{padding-left:9px;padding-right:9px;-webkit-border-radius:9px;-moz-border-radius:9px;border-radius:9px;} +.label:empty,.badge:empty{display:none;} +a.label:hover,a.label:focus,a.badge:hover,a.badge:focus{color:#ffffff;text-decoration:none;cursor:pointer;} +.label-important,.badge-important{background-color:#b94a48;} +.label-important[href],.badge-important[href]{background-color:#953b39;} +.label-warning,.badge-warning{background-color:#f89406;} +.label-warning[href],.badge-warning[href]{background-color:#c67605;} +.label-success,.badge-success{background-color:#468847;} +.label-success[href],.badge-success[href]{background-color:#356635;} +.label-info,.badge-info{background-color:#3a87ad;} +.label-info[href],.badge-info[href]{background-color:#2d6987;} +.label-inverse,.badge-inverse{background-color:#333333;} +.label-inverse[href],.badge-inverse[href]{background-color:#1a1a1a;} +.btn .label,.btn .badge{position:relative;top:-1px;} +.btn-mini .label,.btn-mini .badge{top:0;} +table{max-width:100%;background-color:transparent;border-collapse:collapse;border-spacing:0;} +.table{width:100%;margin-bottom:20px;}.table th,.table td{padding:8px;line-height:20px;text-align:left;vertical-align:top;border-top:1px solid #dddddd;} +.table th{font-weight:bold;} +.table thead th{vertical-align:bottom;} +.table caption+thead tr:first-child th,.table caption+thead tr:first-child td,.table colgroup+thead tr:first-child th,.table colgroup+thead tr:first-child td,.table thead:first-child tr:first-child th,.table thead:first-child tr:first-child td{border-top:0;} +.table tbody+tbody{border-top:2px solid #dddddd;} +.table .table{background-color:#ffffff;} +.table-condensed th,.table-condensed td{padding:4px 5px;} +.table-bordered{border:1px solid #dddddd;border-collapse:separate;*border-collapse:collapse;border-left:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.table-bordered th,.table-bordered td{border-left:1px solid #dddddd;} +.table-bordered caption+thead tr:first-child th,.table-bordered caption+tbody tr:first-child th,.table-bordered caption+tbody tr:first-child td,.table-bordered colgroup+thead tr:first-child th,.table-bordered colgroup+tbody tr:first-child th,.table-bordered colgroup+tbody tr:first-child td,.table-bordered thead:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child th,.table-bordered tbody:first-child tr:first-child td{border-top:0;} +.table-bordered thead:first-child tr:first-child>th:first-child,.table-bordered tbody:first-child tr:first-child>td:first-child,.table-bordered tbody:first-child tr:first-child>th:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.table-bordered thead:first-child tr:first-child>th:last-child,.table-bordered tbody:first-child tr:first-child>td:last-child,.table-bordered tbody:first-child tr:first-child>th:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} +.table-bordered thead:last-child tr:last-child>th:first-child,.table-bordered tbody:last-child tr:last-child>td:first-child,.table-bordered tbody:last-child tr:last-child>th:first-child,.table-bordered tfoot:last-child tr:last-child>td:first-child,.table-bordered tfoot:last-child tr:last-child>th:first-child{-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.table-bordered thead:last-child tr:last-child>th:last-child,.table-bordered tbody:last-child tr:last-child>td:last-child,.table-bordered tbody:last-child tr:last-child>th:last-child,.table-bordered tfoot:last-child tr:last-child>td:last-child,.table-bordered tfoot:last-child tr:last-child>th:last-child{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.table-bordered tfoot+tbody:last-child tr:last-child td:first-child{-webkit-border-bottom-left-radius:0;-moz-border-radius-bottomleft:0;border-bottom-left-radius:0;} +.table-bordered tfoot+tbody:last-child tr:last-child td:last-child{-webkit-border-bottom-right-radius:0;-moz-border-radius-bottomright:0;border-bottom-right-radius:0;} +.table-bordered caption+thead tr:first-child th:first-child,.table-bordered caption+tbody tr:first-child td:first-child,.table-bordered colgroup+thead tr:first-child th:first-child,.table-bordered colgroup+tbody tr:first-child td:first-child{-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.table-bordered caption+thead tr:first-child th:last-child,.table-bordered caption+tbody tr:first-child td:last-child,.table-bordered colgroup+thead tr:first-child th:last-child,.table-bordered colgroup+tbody tr:first-child td:last-child{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;} +.table-striped tbody>tr:nth-child(odd)>td,.table-striped tbody>tr:nth-child(odd)>th{background-color:#f9f9f9;} +.table-hover tbody tr:hover>td,.table-hover tbody tr:hover>th{background-color:#f5f5f5;} +table td[class*="span"],table th[class*="span"],.row-fluid table td[class*="span"],.row-fluid table th[class*="span"]{display:table-cell;float:none;margin-left:0;} +.table td.span1,.table th.span1{float:none;width:44px;margin-left:0;} +.table td.span2,.table th.span2{float:none;width:124px;margin-left:0;} +.table td.span3,.table th.span3{float:none;width:204px;margin-left:0;} +.table td.span4,.table th.span4{float:none;width:284px;margin-left:0;} +.table td.span5,.table th.span5{float:none;width:364px;margin-left:0;} +.table td.span6,.table th.span6{float:none;width:444px;margin-left:0;} +.table td.span7,.table th.span7{float:none;width:524px;margin-left:0;} +.table td.span8,.table th.span8{float:none;width:604px;margin-left:0;} +.table td.span9,.table th.span9{float:none;width:684px;margin-left:0;} +.table td.span10,.table th.span10{float:none;width:764px;margin-left:0;} +.table td.span11,.table th.span11{float:none;width:844px;margin-left:0;} +.table td.span12,.table th.span12{float:none;width:924px;margin-left:0;} +.table tbody tr.success>td{background-color:#dff0d8;} +.table tbody tr.error>td{background-color:#f2dede;} +.table tbody tr.warning>td{background-color:#fcf8e3;} +.table tbody tr.info>td{background-color:#d9edf7;} +.table-hover tbody tr.success:hover>td{background-color:#d0e9c6;} +.table-hover tbody tr.error:hover>td{background-color:#ebcccc;} +.table-hover tbody tr.warning:hover>td{background-color:#faf2cc;} +.table-hover tbody tr.info:hover>td{background-color:#c4e3f3;} +form{margin:0 0 20px;} +fieldset{padding:0;margin:0;border:0;} +legend{display:block;width:100%;padding:0;margin-bottom:20px;font-size:21px;line-height:40px;color:#333333;border:0;border-bottom:1px solid #e5e5e5;}legend small{font-size:15px;color:#999999;} +label,input,button,select,textarea{font-size:14px;font-weight:normal;line-height:20px;} +input,button,select,textarea{font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;} +label{display:block;margin-bottom:5px;} +select,textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{display:inline-block;height:20px;padding:4px 6px;margin-bottom:10px;font-size:14px;line-height:20px;color:#555555;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;vertical-align:middle;} +input,textarea,.uneditable-input{width:206px;} +textarea{height:auto;} +textarea,input[type="text"],input[type="password"],input[type="datetime"],input[type="datetime-local"],input[type="date"],input[type="month"],input[type="time"],input[type="week"],input[type="number"],input[type="email"],input[type="url"],input[type="search"],input[type="tel"],input[type="color"],.uneditable-input{background-color:#ffffff;border:1px solid #cccccc;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-webkit-transition:border linear .2s, box-shadow linear .2s;-moz-transition:border linear .2s, box-shadow linear .2s;-o-transition:border linear .2s, box-shadow linear .2s;transition:border linear .2s, box-shadow linear .2s;}textarea:focus,input[type="text"]:focus,input[type="password"]:focus,input[type="datetime"]:focus,input[type="datetime-local"]:focus,input[type="date"]:focus,input[type="month"]:focus,input[type="time"]:focus,input[type="week"]:focus,input[type="number"]:focus,input[type="email"]:focus,input[type="url"]:focus,input[type="search"]:focus,input[type="tel"]:focus,input[type="color"]:focus,.uneditable-input:focus{border-color:rgba(82, 168, 236, 0.8);outline:0;outline:thin dotted \9;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);-moz-box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(82,168,236,.6);} +input[type="radio"],input[type="checkbox"]{margin:4px 0 0;*margin-top:0;margin-top:1px \9;line-height:normal;} +input[type="file"],input[type="image"],input[type="submit"],input[type="reset"],input[type="button"],input[type="radio"],input[type="checkbox"]{width:auto;} +select,input[type="file"]{height:30px;*margin-top:4px;line-height:30px;} +select{width:220px;border:1px solid #cccccc;background-color:#ffffff;} +select[multiple],select[size]{height:auto;} +select:focus,input[type="file"]:focus,input[type="radio"]:focus,input[type="checkbox"]:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.uneditable-input,.uneditable-textarea{color:#999999;background-color:#fcfcfc;border-color:#cccccc;-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.025);cursor:not-allowed;} +.uneditable-input{overflow:hidden;white-space:nowrap;} +.uneditable-textarea{width:auto;height:auto;} +input:-moz-placeholder,textarea:-moz-placeholder{color:#999999;} +input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#999999;} +input::-webkit-input-placeholder,textarea::-webkit-input-placeholder{color:#999999;} +.radio,.checkbox{min-height:20px;padding-left:20px;} +.radio input[type="radio"],.checkbox input[type="checkbox"]{float:left;margin-left:-20px;} +.controls>.radio:first-child,.controls>.checkbox:first-child{padding-top:5px;} +.radio.inline,.checkbox.inline{display:inline-block;padding-top:5px;margin-bottom:0;vertical-align:middle;} +.radio.inline+.radio.inline,.checkbox.inline+.checkbox.inline{margin-left:10px;} +.input-mini{width:60px;} +.input-small{width:90px;} +.input-medium{width:150px;} +.input-large{width:210px;} +.input-xlarge{width:270px;} +.input-xxlarge{width:530px;} +input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"]{float:none;margin-left:0;} +.input-append input[class*="span"],.input-append .uneditable-input[class*="span"],.input-prepend input[class*="span"],.input-prepend .uneditable-input[class*="span"],.row-fluid input[class*="span"],.row-fluid select[class*="span"],.row-fluid textarea[class*="span"],.row-fluid .uneditable-input[class*="span"],.row-fluid .input-prepend [class*="span"],.row-fluid .input-append [class*="span"]{display:inline-block;} +input,textarea,.uneditable-input{margin-left:0;} +.controls-row [class*="span"]+[class*="span"]{margin-left:20px;} +input.span12,textarea.span12,.uneditable-input.span12{width:926px;} +input.span11,textarea.span11,.uneditable-input.span11{width:846px;} +input.span10,textarea.span10,.uneditable-input.span10{width:766px;} +input.span9,textarea.span9,.uneditable-input.span9{width:686px;} +input.span8,textarea.span8,.uneditable-input.span8{width:606px;} +input.span7,textarea.span7,.uneditable-input.span7{width:526px;} +input.span6,textarea.span6,.uneditable-input.span6{width:446px;} +input.span5,textarea.span5,.uneditable-input.span5{width:366px;} +input.span4,textarea.span4,.uneditable-input.span4{width:286px;} +input.span3,textarea.span3,.uneditable-input.span3{width:206px;} +input.span2,textarea.span2,.uneditable-input.span2{width:126px;} +input.span1,textarea.span1,.uneditable-input.span1{width:46px;} +.controls-row{*zoom:1;}.controls-row:before,.controls-row:after{display:table;content:"";line-height:0;} +.controls-row:after{clear:both;} +.controls-row [class*="span"],.row-fluid .controls-row [class*="span"]{float:left;} +.controls-row .checkbox[class*="span"],.controls-row .radio[class*="span"]{padding-top:5px;} +input[disabled],select[disabled],textarea[disabled],input[readonly],select[readonly],textarea[readonly]{cursor:not-allowed;background-color:#eeeeee;} +input[type="radio"][disabled],input[type="checkbox"][disabled],input[type="radio"][readonly],input[type="checkbox"][readonly]{background-color:transparent;} +.control-group.warning .control-label,.control-group.warning .help-block,.control-group.warning .help-inline{color:#c09853;} +.control-group.warning .checkbox,.control-group.warning .radio,.control-group.warning input,.control-group.warning select,.control-group.warning textarea{color:#c09853;} +.control-group.warning input,.control-group.warning select,.control-group.warning textarea{border-color:#c09853;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.warning input:focus,.control-group.warning select:focus,.control-group.warning textarea:focus{border-color:#a47e3c;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #dbc59e;} +.control-group.warning .input-prepend .add-on,.control-group.warning .input-append .add-on{color:#c09853;background-color:#fcf8e3;border-color:#c09853;} +.control-group.error .control-label,.control-group.error .help-block,.control-group.error .help-inline{color:#b94a48;} +.control-group.error .checkbox,.control-group.error .radio,.control-group.error input,.control-group.error select,.control-group.error textarea{color:#b94a48;} +.control-group.error input,.control-group.error select,.control-group.error textarea{border-color:#b94a48;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.error input:focus,.control-group.error select:focus,.control-group.error textarea:focus{border-color:#953b39;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #d59392;} +.control-group.error .input-prepend .add-on,.control-group.error .input-append .add-on{color:#b94a48;background-color:#f2dede;border-color:#b94a48;} +.control-group.success .control-label,.control-group.success .help-block,.control-group.success .help-inline{color:#468847;} +.control-group.success .checkbox,.control-group.success .radio,.control-group.success input,.control-group.success select,.control-group.success textarea{color:#468847;} +.control-group.success input,.control-group.success select,.control-group.success textarea{border-color:#468847;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.success input:focus,.control-group.success select:focus,.control-group.success textarea:focus{border-color:#356635;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7aba7b;} +.control-group.success .input-prepend .add-on,.control-group.success .input-append .add-on{color:#468847;background-color:#dff0d8;border-color:#468847;} +.control-group.info .control-label,.control-group.info .help-block,.control-group.info .help-inline{color:#3a87ad;} +.control-group.info .checkbox,.control-group.info .radio,.control-group.info input,.control-group.info select,.control-group.info textarea{color:#3a87ad;} +.control-group.info input,.control-group.info select,.control-group.info textarea{border-color:#3a87ad;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075);}.control-group.info input:focus,.control-group.info select:focus,.control-group.info textarea:focus{border-color:#2d6987;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.075),0 0 6px #7ab5d3;} +.control-group.info .input-prepend .add-on,.control-group.info .input-append .add-on{color:#3a87ad;background-color:#d9edf7;border-color:#3a87ad;} +input:focus:invalid,textarea:focus:invalid,select:focus:invalid{color:#b94a48;border-color:#ee5f5b;}input:focus:invalid:focus,textarea:focus:invalid:focus,select:focus:invalid:focus{border-color:#e9322d;-webkit-box-shadow:0 0 6px #f8b9b7;-moz-box-shadow:0 0 6px #f8b9b7;box-shadow:0 0 6px #f8b9b7;} +.form-actions{padding:19px 20px 20px;margin-top:20px;margin-bottom:20px;background-color:#f5f5f5;border-top:1px solid #e5e5e5;*zoom:1;}.form-actions:before,.form-actions:after{display:table;content:"";line-height:0;} +.form-actions:after{clear:both;} +.help-block,.help-inline{color:#595959;} +.help-block{display:block;margin-bottom:10px;} +.help-inline{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding-left:5px;} +.input-append,.input-prepend{display:inline-block;margin-bottom:10px;vertical-align:middle;font-size:0;white-space:nowrap;}.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input,.input-append .dropdown-menu,.input-prepend .dropdown-menu,.input-append .popover,.input-prepend .popover{font-size:14px;} +.input-append input,.input-prepend input,.input-append select,.input-prepend select,.input-append .uneditable-input,.input-prepend .uneditable-input{position:relative;margin-bottom:0;*margin-left:0;vertical-align:top;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;}.input-append input:focus,.input-prepend input:focus,.input-append select:focus,.input-prepend select:focus,.input-append .uneditable-input:focus,.input-prepend .uneditable-input:focus{z-index:2;} +.input-append .add-on,.input-prepend .add-on{display:inline-block;width:auto;height:20px;min-width:16px;padding:4px 5px;font-size:14px;font-weight:normal;line-height:20px;text-align:center;text-shadow:0 1px 0 #ffffff;background-color:#eeeeee;border:1px solid #ccc;} +.input-append .add-on,.input-prepend .add-on,.input-append .btn,.input-prepend .btn,.input-append .btn-group>.dropdown-toggle,.input-prepend .btn-group>.dropdown-toggle{vertical-align:top;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.input-append .active,.input-prepend .active{background-color:#a9dba9;border-color:#46a546;} +.input-prepend .add-on,.input-prepend .btn{margin-right:-1px;} +.input-prepend .add-on:first-child,.input-prepend .btn:first-child{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.input-append input,.input-append select,.input-append .uneditable-input{-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;}.input-append input+.btn-group .btn:last-child,.input-append select+.btn-group .btn:last-child,.input-append .uneditable-input+.btn-group .btn:last-child{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-append .add-on,.input-append .btn,.input-append .btn-group{margin-left:-1px;} +.input-append .add-on:last-child,.input-append .btn:last-child,.input-append .btn-group:last-child>.dropdown-toggle{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append input,.input-prepend.input-append select,.input-prepend.input-append .uneditable-input{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;}.input-prepend.input-append input+.btn-group .btn,.input-prepend.input-append select+.btn-group .btn,.input-prepend.input-append .uneditable-input+.btn-group .btn{-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append .add-on:first-child,.input-prepend.input-append .btn:first-child{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.input-prepend.input-append .add-on:last-child,.input-prepend.input-append .btn:last-child{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.input-prepend.input-append .btn-group:first-child{margin-left:0;} +input.search-query{padding-right:14px;padding-right:4px \9;padding-left:14px;padding-left:4px \9;margin-bottom:0;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.form-search .input-append .search-query,.form-search .input-prepend .search-query{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.form-search .input-append .search-query{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} +.form-search .input-append .btn{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} +.form-search .input-prepend .search-query{-webkit-border-radius:0 14px 14px 0;-moz-border-radius:0 14px 14px 0;border-radius:0 14px 14px 0;} +.form-search .input-prepend .btn{-webkit-border-radius:14px 0 0 14px;-moz-border-radius:14px 0 0 14px;border-radius:14px 0 0 14px;} +.form-search input,.form-inline input,.form-horizontal input,.form-search textarea,.form-inline textarea,.form-horizontal textarea,.form-search select,.form-inline select,.form-horizontal select,.form-search .help-inline,.form-inline .help-inline,.form-horizontal .help-inline,.form-search .uneditable-input,.form-inline .uneditable-input,.form-horizontal .uneditable-input,.form-search .input-prepend,.form-inline .input-prepend,.form-horizontal .input-prepend,.form-search .input-append,.form-inline .input-append,.form-horizontal .input-append{display:inline-block;*display:inline;*zoom:1;margin-bottom:0;vertical-align:middle;} +.form-search .hide,.form-inline .hide,.form-horizontal .hide{display:none;} +.form-search label,.form-inline label,.form-search .btn-group,.form-inline .btn-group{display:inline-block;} +.form-search .input-append,.form-inline .input-append,.form-search .input-prepend,.form-inline .input-prepend{margin-bottom:0;} +.form-search .radio,.form-search .checkbox,.form-inline .radio,.form-inline .checkbox{padding-left:0;margin-bottom:0;vertical-align:middle;} +.form-search .radio input[type="radio"],.form-search .checkbox input[type="checkbox"],.form-inline .radio input[type="radio"],.form-inline .checkbox input[type="checkbox"]{float:left;margin-right:3px;margin-left:0;} +.control-group{margin-bottom:10px;} +legend+.control-group{margin-top:20px;-webkit-margin-top-collapse:separate;} +.form-horizontal .control-group{margin-bottom:20px;*zoom:1;}.form-horizontal .control-group:before,.form-horizontal .control-group:after{display:table;content:"";line-height:0;} +.form-horizontal .control-group:after{clear:both;} +.form-horizontal .control-label{float:left;width:160px;padding-top:5px;text-align:right;} +.form-horizontal .controls{*display:inline-block;*padding-left:20px;margin-left:180px;*margin-left:0;}.form-horizontal .controls:first-child{*padding-left:180px;} +.form-horizontal .help-block{margin-bottom:0;} +.form-horizontal input+.help-block,.form-horizontal select+.help-block,.form-horizontal textarea+.help-block,.form-horizontal .uneditable-input+.help-block,.form-horizontal .input-prepend+.help-block,.form-horizontal .input-append+.help-block{margin-top:10px;} +.form-horizontal .form-actions{padding-left:180px;} +.btn{display:inline-block;*display:inline;*zoom:1;padding:4px 12px;margin-bottom:0;font-size:14px;line-height:20px;text-align:center;vertical-align:middle;cursor:pointer;color:#333333;text-shadow:0 1px 1px rgba(255, 255, 255, 0.75);background-color:#f5f5f5;background-image:-moz-linear-gradient(top, #ffffff, #e6e6e6);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));background-image:-webkit-linear-gradient(top, #ffffff, #e6e6e6);background-image:-o-linear-gradient(top, #ffffff, #e6e6e6);background-image:linear-gradient(to bottom, #ffffff, #e6e6e6);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe6e6e6', GradientType=0);border-color:#e6e6e6 #e6e6e6 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e6e6e6;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);border:1px solid #cccccc;*border:0;border-bottom-color:#b3b3b3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;*margin-left:.3em;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);}.btn:hover,.btn:focus,.btn:active,.btn.active,.btn.disabled,.btn[disabled]{color:#333333;background-color:#e6e6e6;*background-color:#d9d9d9;} +.btn:active,.btn.active{background-color:#cccccc \9;} +.btn:first-child{*margin-left:0;} +.btn:hover,.btn:focus{color:#333333;text-decoration:none;background-position:0 -15px;-webkit-transition:background-position 0.1s linear;-moz-transition:background-position 0.1s linear;-o-transition:background-position 0.1s linear;transition:background-position 0.1s linear;} +.btn:focus{outline:thin dotted #333;outline:5px auto -webkit-focus-ring-color;outline-offset:-2px;} +.btn.active,.btn:active{background-image:none;outline:0;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} +.btn.disabled,.btn[disabled]{cursor:default;background-image:none;opacity:0.65;filter:alpha(opacity=65);-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-large{padding:11px 19px;font-size:17.5px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.btn-large [class^="icon-"],.btn-large [class*=" icon-"]{margin-top:4px;} +.btn-small{padding:2px 10px;font-size:11.9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.btn-small [class^="icon-"],.btn-small [class*=" icon-"]{margin-top:0;} +.btn-mini [class^="icon-"],.btn-mini [class*=" icon-"]{margin-top:-1px;} +.btn-mini{padding:0 6px;font-size:10.5px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.btn-block{display:block;width:100%;padding-left:0;padding-right:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} +.btn-block+.btn-block{margin-top:5px;} +input[type="submit"].btn-block,input[type="reset"].btn-block,input[type="button"].btn-block{width:100%;} +.btn-primary.active,.btn-warning.active,.btn-danger.active,.btn-success.active,.btn-info.active,.btn-inverse.active{color:rgba(255, 255, 255, 0.75);} +.btn-primary{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#006dcc;background-image:-moz-linear-gradient(top, #0088cc, #0044cc);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0044cc));background-image:-webkit-linear-gradient(top, #0088cc, #0044cc);background-image:-o-linear-gradient(top, #0088cc, #0044cc);background-image:linear-gradient(to bottom, #0088cc, #0044cc);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0044cc', GradientType=0);border-color:#0044cc #0044cc #002a80;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#0044cc;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-primary:hover,.btn-primary:focus,.btn-primary:active,.btn-primary.active,.btn-primary.disabled,.btn-primary[disabled]{color:#ffffff;background-color:#0044cc;*background-color:#003bb3;} +.btn-primary:active,.btn-primary.active{background-color:#003399 \9;} +.btn-warning{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);border-color:#f89406 #f89406 #ad6704;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#f89406;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-warning:hover,.btn-warning:focus,.btn-warning:active,.btn-warning.active,.btn-warning.disabled,.btn-warning[disabled]{color:#ffffff;background-color:#f89406;*background-color:#df8505;} +.btn-warning:active,.btn-warning.active{background-color:#c67605 \9;} +.btn-danger{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#da4f49;background-image:-moz-linear-gradient(top, #ee5f5b, #bd362f);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#bd362f));background-image:-webkit-linear-gradient(top, #ee5f5b, #bd362f);background-image:-o-linear-gradient(top, #ee5f5b, #bd362f);background-image:linear-gradient(to bottom, #ee5f5b, #bd362f);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffbd362f', GradientType=0);border-color:#bd362f #bd362f #802420;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#bd362f;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-danger:hover,.btn-danger:focus,.btn-danger:active,.btn-danger.active,.btn-danger.disabled,.btn-danger[disabled]{color:#ffffff;background-color:#bd362f;*background-color:#a9302a;} +.btn-danger:active,.btn-danger.active{background-color:#942a25 \9;} +.btn-success{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#5bb75b;background-image:-moz-linear-gradient(top, #62c462, #51a351);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#51a351));background-image:-webkit-linear-gradient(top, #62c462, #51a351);background-image:-o-linear-gradient(top, #62c462, #51a351);background-image:linear-gradient(to bottom, #62c462, #51a351);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff51a351', GradientType=0);border-color:#51a351 #51a351 #387038;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#51a351;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-success:hover,.btn-success:focus,.btn-success:active,.btn-success.active,.btn-success.disabled,.btn-success[disabled]{color:#ffffff;background-color:#51a351;*background-color:#499249;} +.btn-success:active,.btn-success.active{background-color:#408140 \9;} +.btn-info{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#49afcd;background-image:-moz-linear-gradient(top, #5bc0de, #2f96b4);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#2f96b4));background-image:-webkit-linear-gradient(top, #5bc0de, #2f96b4);background-image:-o-linear-gradient(top, #5bc0de, #2f96b4);background-image:linear-gradient(to bottom, #5bc0de, #2f96b4);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2f96b4', GradientType=0);border-color:#2f96b4 #2f96b4 #1f6377;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#2f96b4;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-info:hover,.btn-info:focus,.btn-info:active,.btn-info.active,.btn-info.disabled,.btn-info[disabled]{color:#ffffff;background-color:#2f96b4;*background-color:#2a85a0;} +.btn-info:active,.btn-info.active{background-color:#24748c \9;} +.btn-inverse{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#363636;background-image:-moz-linear-gradient(top, #444444, #222222);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#444444), to(#222222));background-image:-webkit-linear-gradient(top, #444444, #222222);background-image:-o-linear-gradient(top, #444444, #222222);background-image:linear-gradient(to bottom, #444444, #222222);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff444444', endColorstr='#ff222222', GradientType=0);border-color:#222222 #222222 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#222222;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.btn-inverse:hover,.btn-inverse:focus,.btn-inverse:active,.btn-inverse.active,.btn-inverse.disabled,.btn-inverse[disabled]{color:#ffffff;background-color:#222222;*background-color:#151515;} +.btn-inverse:active,.btn-inverse.active{background-color:#080808 \9;} +button.btn,input[type="submit"].btn{*padding-top:3px;*padding-bottom:3px;}button.btn::-moz-focus-inner,input[type="submit"].btn::-moz-focus-inner{padding:0;border:0;} +button.btn.btn-large,input[type="submit"].btn.btn-large{*padding-top:7px;*padding-bottom:7px;} +button.btn.btn-small,input[type="submit"].btn.btn-small{*padding-top:3px;*padding-bottom:3px;} +button.btn.btn-mini,input[type="submit"].btn.btn-mini{*padding-top:1px;*padding-bottom:1px;} +.btn-link,.btn-link:active,.btn-link[disabled]{background-color:transparent;background-image:none;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} +.btn-link{border-color:transparent;cursor:pointer;color:#0088cc;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-link:hover,.btn-link:focus{color:#005580;text-decoration:underline;background-color:transparent;} +.btn-link[disabled]:hover,.btn-link[disabled]:focus{color:#333333;text-decoration:none;} +.btn-group{position:relative;display:inline-block;*display:inline;*zoom:1;font-size:0;vertical-align:middle;white-space:nowrap;*margin-left:.3em;}.btn-group:first-child{*margin-left:0;} +.btn-group+.btn-group{margin-left:5px;} +.btn-toolbar{font-size:0;margin-top:10px;margin-bottom:10px;}.btn-toolbar>.btn+.btn,.btn-toolbar>.btn-group+.btn,.btn-toolbar>.btn+.btn-group{margin-left:5px;} +.btn-group>.btn{position:relative;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group>.btn+.btn{margin-left:-1px;} +.btn-group>.btn,.btn-group>.dropdown-menu,.btn-group>.popover{font-size:14px;} +.btn-group>.btn-mini{font-size:10.5px;} +.btn-group>.btn-small{font-size:11.9px;} +.btn-group>.btn-large{font-size:17.5px;} +.btn-group>.btn:first-child{margin-left:0;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.btn-group>.btn:last-child,.btn-group>.dropdown-toggle{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.btn-group>.btn.large:first-child{margin-left:0;-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.btn-group>.btn.large:last-child,.btn-group>.large.dropdown-toggle{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.btn-group>.btn:hover,.btn-group>.btn:focus,.btn-group>.btn:active,.btn-group>.btn.active{z-index:2;} +.btn-group .dropdown-toggle:active,.btn-group.open .dropdown-toggle{outline:0;} +.btn-group>.btn+.dropdown-toggle{padding-left:8px;padding-right:8px;-webkit-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 1px 0 0 rgba(255,255,255,.125), inset 0 1px 0 rgba(255,255,255,.2), 0 1px 2px rgba(0,0,0,.05);*padding-top:5px;*padding-bottom:5px;} +.btn-group>.btn-mini+.dropdown-toggle{padding-left:5px;padding-right:5px;*padding-top:2px;*padding-bottom:2px;} +.btn-group>.btn-small+.dropdown-toggle{*padding-top:5px;*padding-bottom:4px;} +.btn-group>.btn-large+.dropdown-toggle{padding-left:12px;padding-right:12px;*padding-top:7px;*padding-bottom:7px;} +.btn-group.open .dropdown-toggle{background-image:none;-webkit-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);-moz-box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);} +.btn-group.open .btn.dropdown-toggle{background-color:#e6e6e6;} +.btn-group.open .btn-primary.dropdown-toggle{background-color:#0044cc;} +.btn-group.open .btn-warning.dropdown-toggle{background-color:#f89406;} +.btn-group.open .btn-danger.dropdown-toggle{background-color:#bd362f;} +.btn-group.open .btn-success.dropdown-toggle{background-color:#51a351;} +.btn-group.open .btn-info.dropdown-toggle{background-color:#2f96b4;} +.btn-group.open .btn-inverse.dropdown-toggle{background-color:#222222;} +.btn .caret{margin-top:8px;margin-left:0;} +.btn-large .caret{margin-top:6px;} +.btn-large .caret{border-left-width:5px;border-right-width:5px;border-top-width:5px;} +.btn-mini .caret,.btn-small .caret{margin-top:8px;} +.dropup .btn-large .caret{border-bottom-width:5px;} +.btn-primary .caret,.btn-warning .caret,.btn-danger .caret,.btn-info .caret,.btn-success .caret,.btn-inverse .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.btn-group-vertical{display:inline-block;*display:inline;*zoom:1;} +.btn-group-vertical>.btn{display:block;float:none;max-width:100%;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.btn-group-vertical>.btn+.btn{margin-left:0;margin-top:-1px;} +.btn-group-vertical>.btn:first-child{-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;} +.btn-group-vertical>.btn:last-child{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;} +.btn-group-vertical>.btn-large:first-child{-webkit-border-radius:6px 6px 0 0;-moz-border-radius:6px 6px 0 0;border-radius:6px 6px 0 0;} +.btn-group-vertical>.btn-large:last-child{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} +.nav{margin-left:0;margin-bottom:20px;list-style:none;} +.nav>li>a{display:block;} +.nav>li>a:hover,.nav>li>a:focus{text-decoration:none;background-color:#eeeeee;} +.nav>li>a>img{max-width:none;} +.nav>.pull-right{float:right;} +.nav-header{display:block;padding:3px 15px;font-size:11px;font-weight:bold;line-height:20px;color:#999999;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);text-transform:uppercase;} +.nav li+.nav-header{margin-top:9px;} +.nav-list{padding-left:15px;padding-right:15px;margin-bottom:0;} +.nav-list>li>a,.nav-list .nav-header{margin-left:-15px;margin-right:-15px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);} +.nav-list>li>a{padding:3px 15px;} +.nav-list>.active>a,.nav-list>.active>a:hover,.nav-list>.active>a:focus{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.2);background-color:#0088cc;} +.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{margin-right:2px;} +.nav-list .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} +.nav-tabs,.nav-pills{*zoom:1;}.nav-tabs:before,.nav-pills:before,.nav-tabs:after,.nav-pills:after{display:table;content:"";line-height:0;} +.nav-tabs:after,.nav-pills:after{clear:both;} +.nav-tabs>li,.nav-pills>li{float:left;} +.nav-tabs>li>a,.nav-pills>li>a{padding-right:12px;padding-left:12px;margin-right:2px;line-height:14px;} +.nav-tabs{border-bottom:1px solid #ddd;} +.nav-tabs>li{margin-bottom:-1px;} +.nav-tabs>li>a{padding-top:8px;padding-bottom:8px;line-height:20px;border:1px solid transparent;-webkit-border-radius:4px 4px 0 0;-moz-border-radius:4px 4px 0 0;border-radius:4px 4px 0 0;}.nav-tabs>li>a:hover,.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #dddddd;} +.nav-tabs>.active>a,.nav-tabs>.active>a:hover,.nav-tabs>.active>a:focus{color:#555555;background-color:#ffffff;border:1px solid #ddd;border-bottom-color:transparent;cursor:default;} +.nav-pills>li>a{padding-top:8px;padding-bottom:8px;margin-top:2px;margin-bottom:2px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.nav-pills>.active>a,.nav-pills>.active>a:hover,.nav-pills>.active>a:focus{color:#ffffff;background-color:#0088cc;} +.nav-stacked>li{float:none;} +.nav-stacked>li>a{margin-right:0;} +.nav-tabs.nav-stacked{border-bottom:0;} +.nav-tabs.nav-stacked>li>a{border:1px solid #ddd;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.nav-tabs.nav-stacked>li:first-child>a{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;} +.nav-tabs.nav-stacked>li:last-child>a{-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.nav-tabs.nav-stacked>li>a:hover,.nav-tabs.nav-stacked>li>a:focus{border-color:#ddd;z-index:2;} +.nav-pills.nav-stacked>li>a{margin-bottom:3px;} +.nav-pills.nav-stacked>li:last-child>a{margin-bottom:1px;} +.nav-tabs .dropdown-menu{-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;} +.nav-pills .dropdown-menu{-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.nav .dropdown-toggle .caret{border-top-color:#0088cc;border-bottom-color:#0088cc;margin-top:6px;} +.nav .dropdown-toggle:hover .caret,.nav .dropdown-toggle:focus .caret{border-top-color:#005580;border-bottom-color:#005580;} +.nav-tabs .dropdown-toggle .caret{margin-top:8px;} +.nav .active .dropdown-toggle .caret{border-top-color:#fff;border-bottom-color:#fff;} +.nav-tabs .active .dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} +.nav>.dropdown.active>a:hover,.nav>.dropdown.active>a:focus{cursor:pointer;} +.nav-tabs .open .dropdown-toggle,.nav-pills .open .dropdown-toggle,.nav>li.dropdown.open.active>a:hover,.nav>li.dropdown.open.active>a:focus{color:#ffffff;background-color:#999999;border-color:#999999;} +.nav li.dropdown.open .caret,.nav li.dropdown.open.active .caret,.nav li.dropdown.open a:hover .caret,.nav li.dropdown.open a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;opacity:1;filter:alpha(opacity=100);} +.tabs-stacked .open>a:hover,.tabs-stacked .open>a:focus{border-color:#999999;} +.tabbable{*zoom:1;}.tabbable:before,.tabbable:after{display:table;content:"";line-height:0;} +.tabbable:after{clear:both;} +.tab-content{overflow:auto;} +.tabs-below>.nav-tabs,.tabs-right>.nav-tabs,.tabs-left>.nav-tabs{border-bottom:0;} +.tab-content>.tab-pane,.pill-content>.pill-pane{display:none;} +.tab-content>.active,.pill-content>.active{display:block;} +.tabs-below>.nav-tabs{border-top:1px solid #ddd;} +.tabs-below>.nav-tabs>li{margin-top:-1px;margin-bottom:0;} +.tabs-below>.nav-tabs>li>a{-webkit-border-radius:0 0 4px 4px;-moz-border-radius:0 0 4px 4px;border-radius:0 0 4px 4px;}.tabs-below>.nav-tabs>li>a:hover,.tabs-below>.nav-tabs>li>a:focus{border-bottom-color:transparent;border-top-color:#ddd;} +.tabs-below>.nav-tabs>.active>a,.tabs-below>.nav-tabs>.active>a:hover,.tabs-below>.nav-tabs>.active>a:focus{border-color:transparent #ddd #ddd #ddd;} +.tabs-left>.nav-tabs>li,.tabs-right>.nav-tabs>li{float:none;} +.tabs-left>.nav-tabs>li>a,.tabs-right>.nav-tabs>li>a{min-width:74px;margin-right:0;margin-bottom:3px;} +.tabs-left>.nav-tabs{float:left;margin-right:19px;border-right:1px solid #ddd;} +.tabs-left>.nav-tabs>li>a{margin-right:-1px;-webkit-border-radius:4px 0 0 4px;-moz-border-radius:4px 0 0 4px;border-radius:4px 0 0 4px;} +.tabs-left>.nav-tabs>li>a:hover,.tabs-left>.nav-tabs>li>a:focus{border-color:#eeeeee #dddddd #eeeeee #eeeeee;} +.tabs-left>.nav-tabs .active>a,.tabs-left>.nav-tabs .active>a:hover,.tabs-left>.nav-tabs .active>a:focus{border-color:#ddd transparent #ddd #ddd;*border-right-color:#ffffff;} +.tabs-right>.nav-tabs{float:right;margin-left:19px;border-left:1px solid #ddd;} +.tabs-right>.nav-tabs>li>a{margin-left:-1px;-webkit-border-radius:0 4px 4px 0;-moz-border-radius:0 4px 4px 0;border-radius:0 4px 4px 0;} +.tabs-right>.nav-tabs>li>a:hover,.tabs-right>.nav-tabs>li>a:focus{border-color:#eeeeee #eeeeee #eeeeee #dddddd;} +.tabs-right>.nav-tabs .active>a,.tabs-right>.nav-tabs .active>a:hover,.tabs-right>.nav-tabs .active>a:focus{border-color:#ddd #ddd #ddd transparent;*border-left-color:#ffffff;} +.nav>.disabled>a{color:#999999;} +.nav>.disabled>a:hover,.nav>.disabled>a:focus{text-decoration:none;background-color:transparent;cursor:default;} +.navbar{overflow:visible;margin-bottom:20px;*position:relative;*z-index:2;} +.navbar-inner{min-height:40px;padding-left:20px;padding-right:20px;background-color:#fafafa;background-image:-moz-linear-gradient(top, #ffffff, #f2f2f2);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#f2f2f2));background-image:-webkit-linear-gradient(top, #ffffff, #f2f2f2);background-image:-o-linear-gradient(top, #ffffff, #f2f2f2);background-image:linear-gradient(to bottom, #ffffff, #f2f2f2);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff2f2f2', GradientType=0);border:1px solid #d4d4d4;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);-moz-box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);box-shadow:0 1px 4px rgba(0, 0, 0, 0.065);*zoom:1;}.navbar-inner:before,.navbar-inner:after{display:table;content:"";line-height:0;} +.navbar-inner:after{clear:both;} +.navbar .container{width:auto;} +.nav-collapse.collapse{height:auto;overflow:visible;} +.navbar .brand{float:left;display:block;padding:10px 20px 10px;margin-left:-20px;font-size:20px;font-weight:200;color:#777777;text-shadow:0 1px 0 #ffffff;}.navbar .brand:hover,.navbar .brand:focus{text-decoration:none;} +.navbar-text{margin-bottom:0;line-height:40px;color:#777777;} +.navbar-link{color:#777777;}.navbar-link:hover,.navbar-link:focus{color:#333333;} +.navbar .divider-vertical{height:40px;margin:0 9px;border-left:1px solid #f2f2f2;border-right:1px solid #ffffff;} +.navbar .btn,.navbar .btn-group{margin-top:5px;} +.navbar .btn-group .btn,.navbar .input-prepend .btn,.navbar .input-append .btn,.navbar .input-prepend .btn-group,.navbar .input-append .btn-group{margin-top:0;} +.navbar-form{margin-bottom:0;*zoom:1;}.navbar-form:before,.navbar-form:after{display:table;content:"";line-height:0;} +.navbar-form:after{clear:both;} +.navbar-form input,.navbar-form select,.navbar-form .radio,.navbar-form .checkbox{margin-top:5px;} +.navbar-form input,.navbar-form select,.navbar-form .btn{display:inline-block;margin-bottom:0;} +.navbar-form input[type="image"],.navbar-form input[type="checkbox"],.navbar-form input[type="radio"]{margin-top:3px;} +.navbar-form .input-append,.navbar-form .input-prepend{margin-top:5px;white-space:nowrap;}.navbar-form .input-append input,.navbar-form .input-prepend input{margin-top:0;} +.navbar-search{position:relative;float:left;margin-top:5px;margin-bottom:0;}.navbar-search .search-query{margin-bottom:0;padding:4px 14px;font-family:"Helvetica Neue",Helvetica,Arial,sans-serif;font-size:13px;font-weight:normal;line-height:1;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.navbar-static-top{position:static;margin-bottom:0;}.navbar-static-top .navbar-inner{-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-fixed-top,.navbar-fixed-bottom{position:fixed;right:0;left:0;z-index:1030;margin-bottom:0;} +.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{border-width:0 0 1px;} +.navbar-fixed-bottom .navbar-inner{border-width:1px 0 0;} +.navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding-left:0;padding-right:0;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;} +.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:940px;} +.navbar-fixed-top{top:0;} +.navbar-fixed-top .navbar-inner,.navbar-static-top .navbar-inner{-webkit-box-shadow:0 1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 1px 10px rgba(0,0,0,.1);box-shadow:0 1px 10px rgba(0,0,0,.1);} +.navbar-fixed-bottom{bottom:0;}.navbar-fixed-bottom .navbar-inner{-webkit-box-shadow:0 -1px 10px rgba(0,0,0,.1);-moz-box-shadow:0 -1px 10px rgba(0,0,0,.1);box-shadow:0 -1px 10px rgba(0,0,0,.1);} +.navbar .nav{position:relative;left:0;display:block;float:left;margin:0 10px 0 0;} +.navbar .nav.pull-right{float:right;margin-right:0;} +.navbar .nav>li{float:left;} +.navbar .nav>li>a{float:none;padding:10px 15px 10px;color:#777777;text-decoration:none;text-shadow:0 1px 0 #ffffff;} +.navbar .nav .dropdown-toggle .caret{margin-top:8px;} +.navbar .nav>li>a:focus,.navbar .nav>li>a:hover{background-color:transparent;color:#333333;text-decoration:none;} +.navbar .nav>.active>a,.navbar .nav>.active>a:hover,.navbar .nav>.active>a:focus{color:#555555;text-decoration:none;background-color:#e5e5e5;-webkit-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);-moz-box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);box-shadow:inset 0 3px 8px rgba(0, 0, 0, 0.125);} +.navbar .btn-navbar{display:none;float:right;padding:7px 10px;margin-left:5px;margin-right:5px;color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#ededed;background-image:-moz-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f2f2f2), to(#e5e5e5));background-image:-webkit-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:-o-linear-gradient(top, #f2f2f2, #e5e5e5);background-image:linear-gradient(to bottom, #f2f2f2, #e5e5e5);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2f2f2', endColorstr='#ffe5e5e5', GradientType=0);border-color:#e5e5e5 #e5e5e5 #bfbfbf;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#e5e5e5;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.075);}.navbar .btn-navbar:hover,.navbar .btn-navbar:focus,.navbar .btn-navbar:active,.navbar .btn-navbar.active,.navbar .btn-navbar.disabled,.navbar .btn-navbar[disabled]{color:#ffffff;background-color:#e5e5e5;*background-color:#d9d9d9;} +.navbar .btn-navbar:active,.navbar .btn-navbar.active{background-color:#cccccc \9;} +.navbar .btn-navbar .icon-bar{display:block;width:18px;height:2px;background-color:#f5f5f5;-webkit-border-radius:1px;-moz-border-radius:1px;border-radius:1px;-webkit-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);-moz-box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);box-shadow:0 1px 0 rgba(0, 0, 0, 0.25);} +.btn-navbar .icon-bar+.icon-bar{margin-top:3px;} +.navbar .nav>li>.dropdown-menu:before{content:'';display:inline-block;border-left:7px solid transparent;border-right:7px solid transparent;border-bottom:7px solid #ccc;border-bottom-color:rgba(0, 0, 0, 0.2);position:absolute;top:-7px;left:9px;} +.navbar .nav>li>.dropdown-menu:after{content:'';display:inline-block;border-left:6px solid transparent;border-right:6px solid transparent;border-bottom:6px solid #ffffff;position:absolute;top:-6px;left:10px;} +.navbar-fixed-bottom .nav>li>.dropdown-menu:before{border-top:7px solid #ccc;border-top-color:rgba(0, 0, 0, 0.2);border-bottom:0;bottom:-7px;top:auto;} +.navbar-fixed-bottom .nav>li>.dropdown-menu:after{border-top:6px solid #ffffff;border-bottom:0;bottom:-6px;top:auto;} +.navbar .nav li.dropdown>a:hover .caret,.navbar .nav li.dropdown>a:focus .caret{border-top-color:#333333;border-bottom-color:#333333;} +.navbar .nav li.dropdown.open>.dropdown-toggle,.navbar .nav li.dropdown.active>.dropdown-toggle,.navbar .nav li.dropdown.open.active>.dropdown-toggle{background-color:#e5e5e5;color:#555555;} +.navbar .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#777777;border-bottom-color:#777777;} +.navbar .nav li.dropdown.open>.dropdown-toggle .caret,.navbar .nav li.dropdown.active>.dropdown-toggle .caret,.navbar .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#555555;border-bottom-color:#555555;} +.navbar .pull-right>li>.dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right{left:auto;right:0;}.navbar .pull-right>li>.dropdown-menu:before,.navbar .nav>li>.dropdown-menu.pull-right:before{left:auto;right:12px;} +.navbar .pull-right>li>.dropdown-menu:after,.navbar .nav>li>.dropdown-menu.pull-right:after{left:auto;right:13px;} +.navbar .pull-right>li>.dropdown-menu .dropdown-menu,.navbar .nav>li>.dropdown-menu.pull-right .dropdown-menu{left:auto;right:100%;margin-left:0;margin-right:-1px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} +.navbar-inverse .navbar-inner{background-color:#1b1b1b;background-image:-moz-linear-gradient(top, #222222, #111111);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#222222), to(#111111));background-image:-webkit-linear-gradient(top, #222222, #111111);background-image:-o-linear-gradient(top, #222222, #111111);background-image:linear-gradient(to bottom, #222222, #111111);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff222222', endColorstr='#ff111111', GradientType=0);border-color:#252525;} +.navbar-inverse .brand,.navbar-inverse .nav>li>a{color:#999999;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);}.navbar-inverse .brand:hover,.navbar-inverse .nav>li>a:hover,.navbar-inverse .brand:focus,.navbar-inverse .nav>li>a:focus{color:#ffffff;} +.navbar-inverse .brand{color:#999999;} +.navbar-inverse .navbar-text{color:#999999;} +.navbar-inverse .nav>li>a:focus,.navbar-inverse .nav>li>a:hover{background-color:transparent;color:#ffffff;} +.navbar-inverse .nav .active>a,.navbar-inverse .nav .active>a:hover,.navbar-inverse .nav .active>a:focus{color:#ffffff;background-color:#111111;} +.navbar-inverse .navbar-link{color:#999999;}.navbar-inverse .navbar-link:hover,.navbar-inverse .navbar-link:focus{color:#ffffff;} +.navbar-inverse .divider-vertical{border-left-color:#111111;border-right-color:#222222;} +.navbar-inverse .nav li.dropdown.open>.dropdown-toggle,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle{background-color:#111111;color:#ffffff;} +.navbar-inverse .nav li.dropdown>a:hover .caret,.navbar-inverse .nav li.dropdown>a:focus .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar-inverse .nav li.dropdown>.dropdown-toggle .caret{border-top-color:#999999;border-bottom-color:#999999;} +.navbar-inverse .nav li.dropdown.open>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.active>.dropdown-toggle .caret,.navbar-inverse .nav li.dropdown.open.active>.dropdown-toggle .caret{border-top-color:#ffffff;border-bottom-color:#ffffff;} +.navbar-inverse .navbar-search .search-query{color:#ffffff;background-color:#515151;border-color:#111111;-webkit-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-moz-box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);box-shadow:inset 0 1px 2px rgba(0,0,0,.1), 0 1px 0 rgba(255,255,255,.15);-webkit-transition:none;-moz-transition:none;-o-transition:none;transition:none;}.navbar-inverse .navbar-search .search-query:-moz-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query:-ms-input-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query::-webkit-input-placeholder{color:#cccccc;} +.navbar-inverse .navbar-search .search-query:focus,.navbar-inverse .navbar-search .search-query.focused{padding:5px 15px;color:#333333;text-shadow:0 1px 0 #ffffff;background-color:#ffffff;border:0;-webkit-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);-moz-box-shadow:0 0 3px rgba(0, 0, 0, 0.15);box-shadow:0 0 3px rgba(0, 0, 0, 0.15);outline:0;} +.navbar-inverse .btn-navbar{color:#ffffff;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e0e0e;background-image:-moz-linear-gradient(top, #151515, #040404);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#151515), to(#040404));background-image:-webkit-linear-gradient(top, #151515, #040404);background-image:-o-linear-gradient(top, #151515, #040404);background-image:linear-gradient(to bottom, #151515, #040404);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff151515', endColorstr='#ff040404', GradientType=0);border-color:#040404 #040404 #000000;border-color:rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);*background-color:#040404;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);}.navbar-inverse .btn-navbar:hover,.navbar-inverse .btn-navbar:focus,.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active,.navbar-inverse .btn-navbar.disabled,.navbar-inverse .btn-navbar[disabled]{color:#ffffff;background-color:#040404;*background-color:#000000;} +.navbar-inverse .btn-navbar:active,.navbar-inverse .btn-navbar.active{background-color:#000000 \9;} +.breadcrumb{padding:8px 15px;margin:0 0 20px;list-style:none;background-color:#f5f5f5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;}.breadcrumb>li{display:inline-block;*display:inline;*zoom:1;text-shadow:0 1px 0 #ffffff;}.breadcrumb>li>.divider{padding:0 5px;color:#ccc;} +.breadcrumb>.active{color:#999999;} +.pagination{margin:20px 0;} +.pagination ul{display:inline-block;*display:inline;*zoom:1;margin-left:0;margin-bottom:0;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);-moz-box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);box-shadow:0 1px 2px rgba(0, 0, 0, 0.05);} +.pagination ul>li{display:inline;} +.pagination ul>li>a,.pagination ul>li>span{float:left;padding:4px 12px;line-height:20px;text-decoration:none;background-color:#ffffff;border:1px solid #dddddd;border-left-width:0;} +.pagination ul>li>a:hover,.pagination ul>li>a:focus,.pagination ul>.active>a,.pagination ul>.active>span{background-color:#f5f5f5;} +.pagination ul>.active>a,.pagination ul>.active>span{color:#999999;cursor:default;} +.pagination ul>.disabled>span,.pagination ul>.disabled>a,.pagination ul>.disabled>a:hover,.pagination ul>.disabled>a:focus{color:#999999;background-color:transparent;cursor:default;} +.pagination ul>li:first-child>a,.pagination ul>li:first-child>span{border-left-width:1px;-webkit-border-top-left-radius:4px;-moz-border-radius-topleft:4px;border-top-left-radius:4px;-webkit-border-bottom-left-radius:4px;-moz-border-radius-bottomleft:4px;border-bottom-left-radius:4px;} +.pagination ul>li:last-child>a,.pagination ul>li:last-child>span{-webkit-border-top-right-radius:4px;-moz-border-radius-topright:4px;border-top-right-radius:4px;-webkit-border-bottom-right-radius:4px;-moz-border-radius-bottomright:4px;border-bottom-right-radius:4px;} +.pagination-centered{text-align:center;} +.pagination-right{text-align:right;} +.pagination-large ul>li>a,.pagination-large ul>li>span{padding:11px 19px;font-size:17.5px;} +.pagination-large ul>li:first-child>a,.pagination-large ul>li:first-child>span{-webkit-border-top-left-radius:6px;-moz-border-radius-topleft:6px;border-top-left-radius:6px;-webkit-border-bottom-left-radius:6px;-moz-border-radius-bottomleft:6px;border-bottom-left-radius:6px;} +.pagination-large ul>li:last-child>a,.pagination-large ul>li:last-child>span{-webkit-border-top-right-radius:6px;-moz-border-radius-topright:6px;border-top-right-radius:6px;-webkit-border-bottom-right-radius:6px;-moz-border-radius-bottomright:6px;border-bottom-right-radius:6px;} +.pagination-mini ul>li:first-child>a,.pagination-small ul>li:first-child>a,.pagination-mini ul>li:first-child>span,.pagination-small ul>li:first-child>span{-webkit-border-top-left-radius:3px;-moz-border-radius-topleft:3px;border-top-left-radius:3px;-webkit-border-bottom-left-radius:3px;-moz-border-radius-bottomleft:3px;border-bottom-left-radius:3px;} +.pagination-mini ul>li:last-child>a,.pagination-small ul>li:last-child>a,.pagination-mini ul>li:last-child>span,.pagination-small ul>li:last-child>span{-webkit-border-top-right-radius:3px;-moz-border-radius-topright:3px;border-top-right-radius:3px;-webkit-border-bottom-right-radius:3px;-moz-border-radius-bottomright:3px;border-bottom-right-radius:3px;} +.pagination-small ul>li>a,.pagination-small ul>li>span{padding:2px 10px;font-size:11.9px;} +.pagination-mini ul>li>a,.pagination-mini ul>li>span{padding:0 6px;font-size:10.5px;} +.pager{margin:20px 0;list-style:none;text-align:center;*zoom:1;}.pager:before,.pager:after{display:table;content:"";line-height:0;} +.pager:after{clear:both;} +.pager li{display:inline;} +.pager li>a,.pager li>span{display:inline-block;padding:5px 14px;background-color:#fff;border:1px solid #ddd;-webkit-border-radius:15px;-moz-border-radius:15px;border-radius:15px;} +.pager li>a:hover,.pager li>a:focus{text-decoration:none;background-color:#f5f5f5;} +.pager .next>a,.pager .next>span{float:right;} +.pager .previous>a,.pager .previous>span{float:left;} +.pager .disabled>a,.pager .disabled>a:hover,.pager .disabled>a:focus,.pager .disabled>span{color:#999999;background-color:#fff;cursor:default;} +.thumbnails{margin-left:-20px;list-style:none;*zoom:1;}.thumbnails:before,.thumbnails:after{display:table;content:"";line-height:0;} +.thumbnails:after{clear:both;} +.row-fluid .thumbnails{margin-left:0;} +.thumbnails>li{float:left;margin-bottom:20px;margin-left:20px;} +.thumbnail{display:block;padding:4px;line-height:20px;border:1px solid #ddd;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-moz-box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);box-shadow:0 1px 3px rgba(0, 0, 0, 0.055);-webkit-transition:all 0.2s ease-in-out;-moz-transition:all 0.2s ease-in-out;-o-transition:all 0.2s ease-in-out;transition:all 0.2s ease-in-out;} +a.thumbnail:hover,a.thumbnail:focus{border-color:#0088cc;-webkit-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);-moz-box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);box-shadow:0 1px 4px rgba(0, 105, 214, 0.25);} +.thumbnail>img{display:block;max-width:100%;margin-left:auto;margin-right:auto;} +.thumbnail .caption{padding:9px;color:#555555;} +.alert{padding:8px 35px 8px 14px;margin-bottom:20px;text-shadow:0 1px 0 rgba(255, 255, 255, 0.5);background-color:#fcf8e3;border:1px solid #fbeed5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.alert,.alert h4{color:#c09853;} +.alert h4{margin:0;} +.alert .close{position:relative;top:-2px;right:-21px;line-height:20px;} +.alert-success{background-color:#dff0d8;border-color:#d6e9c6;color:#468847;} +.alert-success h4{color:#468847;} +.alert-danger,.alert-error{background-color:#f2dede;border-color:#eed3d7;color:#b94a48;} +.alert-danger h4,.alert-error h4{color:#b94a48;} +.alert-info{background-color:#d9edf7;border-color:#bce8f1;color:#3a87ad;} +.alert-info h4{color:#3a87ad;} +.alert-block{padding-top:14px;padding-bottom:14px;} +.alert-block>p,.alert-block>ul{margin-bottom:0;} +.alert-block p+p{margin-top:5px;} +@-webkit-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-moz-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-ms-keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}@-o-keyframes progress-bar-stripes{from{background-position:0 0;} to{background-position:40px 0;}}@keyframes progress-bar-stripes{from{background-position:40px 0;} to{background-position:0 0;}}.progress{overflow:hidden;height:20px;margin-bottom:20px;background-color:#f7f7f7;background-image:-moz-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#f5f5f5), to(#f9f9f9));background-image:-webkit-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:-o-linear-gradient(top, #f5f5f5, #f9f9f9);background-image:linear-gradient(to bottom, #f5f5f5, #f9f9f9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#fff9f9f9', GradientType=0);-webkit-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-moz-box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);box-shadow:inset 0 1px 2px rgba(0, 0, 0, 0.1);-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.progress .bar{width:0%;height:100%;color:#ffffff;float:left;font-size:12px;text-align:center;text-shadow:0 -1px 0 rgba(0, 0, 0, 0.25);background-color:#0e90d2;background-image:-moz-linear-gradient(top, #149bdf, #0480be);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#149bdf), to(#0480be));background-image:-webkit-linear-gradient(top, #149bdf, #0480be);background-image:-o-linear-gradient(top, #149bdf, #0480be);background-image:linear-gradient(to bottom, #149bdf, #0480be);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff149bdf', endColorstr='#ff0480be', GradientType=0);-webkit-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-moz-box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);box-shadow:inset 0 -1px 0 rgba(0, 0, 0, 0.15);-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-transition:width 0.6s ease;-moz-transition:width 0.6s ease;-o-transition:width 0.6s ease;transition:width 0.6s ease;} +.progress .bar+.bar{-webkit-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);-moz-box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);box-shadow:inset 1px 0 0 rgba(0,0,0,.15), inset 0 -1px 0 rgba(0,0,0,.15);} +.progress-striped .bar{background-color:#149bdf;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);-webkit-background-size:40px 40px;-moz-background-size:40px 40px;-o-background-size:40px 40px;background-size:40px 40px;} +.progress.active .bar{-webkit-animation:progress-bar-stripes 2s linear infinite;-moz-animation:progress-bar-stripes 2s linear infinite;-ms-animation:progress-bar-stripes 2s linear infinite;-o-animation:progress-bar-stripes 2s linear infinite;animation:progress-bar-stripes 2s linear infinite;} +.progress-danger .bar,.progress .bar-danger{background-color:#dd514c;background-image:-moz-linear-gradient(top, #ee5f5b, #c43c35);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#ee5f5b), to(#c43c35));background-image:-webkit-linear-gradient(top, #ee5f5b, #c43c35);background-image:-o-linear-gradient(top, #ee5f5b, #c43c35);background-image:linear-gradient(to bottom, #ee5f5b, #c43c35);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffee5f5b', endColorstr='#ffc43c35', GradientType=0);} +.progress-danger.progress-striped .bar,.progress-striped .bar-danger{background-color:#ee5f5b;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-success .bar,.progress .bar-success{background-color:#5eb95e;background-image:-moz-linear-gradient(top, #62c462, #57a957);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#62c462), to(#57a957));background-image:-webkit-linear-gradient(top, #62c462, #57a957);background-image:-o-linear-gradient(top, #62c462, #57a957);background-image:linear-gradient(to bottom, #62c462, #57a957);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff62c462', endColorstr='#ff57a957', GradientType=0);} +.progress-success.progress-striped .bar,.progress-striped .bar-success{background-color:#62c462;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-info .bar,.progress .bar-info{background-color:#4bb1cf;background-image:-moz-linear-gradient(top, #5bc0de, #339bb9);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#5bc0de), to(#339bb9));background-image:-webkit-linear-gradient(top, #5bc0de, #339bb9);background-image:-o-linear-gradient(top, #5bc0de, #339bb9);background-image:linear-gradient(to bottom, #5bc0de, #339bb9);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff339bb9', GradientType=0);} +.progress-info.progress-striped .bar,.progress-striped .bar-info{background-color:#5bc0de;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.progress-warning .bar,.progress .bar-warning{background-color:#faa732;background-image:-moz-linear-gradient(top, #fbb450, #f89406);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#fbb450), to(#f89406));background-image:-webkit-linear-gradient(top, #fbb450, #f89406);background-image:-o-linear-gradient(top, #fbb450, #f89406);background-image:linear-gradient(to bottom, #fbb450, #f89406);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffbb450', endColorstr='#fff89406', GradientType=0);} +.progress-warning.progress-striped .bar,.progress-striped .bar-warning{background-color:#fbb450;background-image:-webkit-gradient(linear, 0 100%, 100% 0, color-stop(0.25, rgba(255, 255, 255, 0.15)), color-stop(0.25, transparent), color-stop(0.5, transparent), color-stop(0.5, rgba(255, 255, 255, 0.15)), color-stop(0.75, rgba(255, 255, 255, 0.15)), color-stop(0.75, transparent), to(transparent));background-image:-webkit-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-moz-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:-o-linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);background-image:linear-gradient(45deg, rgba(255, 255, 255, 0.15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, 0.15) 50%, rgba(255, 255, 255, 0.15) 75%, transparent 75%, transparent);} +.hero-unit{padding:60px;margin-bottom:30px;font-size:18px;font-weight:200;line-height:30px;color:inherit;background-color:#eeeeee;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;}.hero-unit h1{margin-bottom:0;font-size:60px;line-height:1;color:inherit;letter-spacing:-1px;} +.hero-unit li{line-height:30px;} +.media,.media-body{overflow:hidden;*overflow:visible;zoom:1;} +.media,.media .media{margin-top:15px;} +.media:first-child{margin-top:0;} +.media-object{display:block;} +.media-heading{margin:0 0 5px;} +.media>.pull-left{margin-right:10px;} +.media>.pull-right{margin-left:10px;} +.media-list{margin-left:0;list-style:none;} +.tooltip{position:absolute;z-index:1030;display:block;visibility:visible;font-size:11px;line-height:1.4;opacity:0;filter:alpha(opacity=0);}.tooltip.in{opacity:0.8;filter:alpha(opacity=80);} +.tooltip.top{margin-top:-3px;padding:5px 0;} +.tooltip.right{margin-left:3px;padding:0 5px;} +.tooltip.bottom{margin-top:3px;padding:5px 0;} +.tooltip.left{margin-left:-3px;padding:0 5px;} +.tooltip-inner{max-width:200px;padding:8px;color:#ffffff;text-align:center;text-decoration:none;background-color:#000000;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.tooltip-arrow{position:absolute;width:0;height:0;border-color:transparent;border-style:solid;} +.tooltip.top .tooltip-arrow{bottom:0;left:50%;margin-left:-5px;border-width:5px 5px 0;border-top-color:#000000;} +.tooltip.right .tooltip-arrow{top:50%;left:0;margin-top:-5px;border-width:5px 5px 5px 0;border-right-color:#000000;} +.tooltip.left .tooltip-arrow{top:50%;right:0;margin-top:-5px;border-width:5px 0 5px 5px;border-left-color:#000000;} +.tooltip.bottom .tooltip-arrow{top:0;left:50%;margin-left:-5px;border-width:0 5px 5px;border-bottom-color:#000000;} +.popover{position:absolute;top:0;left:0;z-index:1010;display:none;max-width:276px;padding:1px;text-align:left;background-color:#ffffff;-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);white-space:normal;}.popover.top{margin-top:-10px;} +.popover.right{margin-left:10px;} +.popover.bottom{margin-top:10px;} +.popover.left{margin-left:-10px;} +.popover-title{margin:0;padding:8px 14px;font-size:14px;font-weight:normal;line-height:18px;background-color:#f7f7f7;border-bottom:1px solid #ebebeb;-webkit-border-radius:5px 5px 0 0;-moz-border-radius:5px 5px 0 0;border-radius:5px 5px 0 0;}.popover-title:empty{display:none;} +.popover-content{padding:9px 14px;} +.popover .arrow,.popover .arrow:after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid;} +.popover .arrow{border-width:11px;} +.popover .arrow:after{border-width:10px;content:"";} +.popover.top .arrow{left:50%;margin-left:-11px;border-bottom-width:0;border-top-color:#999;border-top-color:rgba(0, 0, 0, 0.25);bottom:-11px;}.popover.top .arrow:after{bottom:1px;margin-left:-10px;border-bottom-width:0;border-top-color:#ffffff;} +.popover.right .arrow{top:50%;left:-11px;margin-top:-11px;border-left-width:0;border-right-color:#999;border-right-color:rgba(0, 0, 0, 0.25);}.popover.right .arrow:after{left:1px;bottom:-10px;border-left-width:0;border-right-color:#ffffff;} +.popover.bottom .arrow{left:50%;margin-left:-11px;border-top-width:0;border-bottom-color:#999;border-bottom-color:rgba(0, 0, 0, 0.25);top:-11px;}.popover.bottom .arrow:after{top:1px;margin-left:-10px;border-top-width:0;border-bottom-color:#ffffff;} +.popover.left .arrow{top:50%;right:-11px;margin-top:-11px;border-right-width:0;border-left-color:#999;border-left-color:rgba(0, 0, 0, 0.25);}.popover.left .arrow:after{right:1px;border-right-width:0;border-left-color:#ffffff;bottom:-10px;} +.modal-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:1040;background-color:#000000;}.modal-backdrop.fade{opacity:0;} +.modal-backdrop,.modal-backdrop.fade.in{opacity:0.8;filter:alpha(opacity=80);} +.modal{position:fixed;top:10%;left:50%;z-index:1050;width:560px;margin-left:-280px;background-color:#ffffff;border:1px solid #999;border:1px solid rgba(0, 0, 0, 0.3);*border:1px solid #999;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-moz-box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);box-shadow:0 3px 7px rgba(0, 0, 0, 0.3);-webkit-background-clip:padding-box;-moz-background-clip:padding-box;background-clip:padding-box;outline:none;}.modal.fade{-webkit-transition:opacity .3s linear, top .3s ease-out;-moz-transition:opacity .3s linear, top .3s ease-out;-o-transition:opacity .3s linear, top .3s ease-out;transition:opacity .3s linear, top .3s ease-out;top:-25%;} +.modal.fade.in{top:10%;} +.modal-header{padding:9px 15px;border-bottom:1px solid #eee;}.modal-header .close{margin-top:2px;} +.modal-header h3{margin:0;line-height:30px;} +.modal-body{position:relative;overflow-y:auto;max-height:400px;padding:15px;} +.modal-form{margin-bottom:0;} +.modal-footer{padding:14px 15px 15px;margin-bottom:0;text-align:right;background-color:#f5f5f5;border-top:1px solid #ddd;-webkit-border-radius:0 0 6px 6px;-moz-border-radius:0 0 6px 6px;border-radius:0 0 6px 6px;-webkit-box-shadow:inset 0 1px 0 #ffffff;-moz-box-shadow:inset 0 1px 0 #ffffff;box-shadow:inset 0 1px 0 #ffffff;*zoom:1;}.modal-footer:before,.modal-footer:after{display:table;content:"";line-height:0;} +.modal-footer:after{clear:both;} +.modal-footer .btn+.btn{margin-left:5px;margin-bottom:0;} +.modal-footer .btn-group .btn+.btn{margin-left:-1px;} +.modal-footer .btn-block+.btn-block{margin-left:0;} +.dropup,.dropdown{position:relative;} +.dropdown-toggle{*margin-bottom:-3px;} +.dropdown-toggle:active,.open .dropdown-toggle{outline:0;} +.caret{display:inline-block;width:0;height:0;vertical-align:top;border-top:4px solid #000000;border-right:4px solid transparent;border-left:4px solid transparent;content:"";} +.dropdown .caret{margin-top:8px;margin-left:2px;} +.dropdown-menu{position:absolute;top:100%;left:0;z-index:1000;display:none;float:left;min-width:160px;padding:5px 0;margin:2px 0 0;list-style:none;background-color:#ffffff;border:1px solid #ccc;border:1px solid rgba(0, 0, 0, 0.2);*border-right-width:2px;*border-bottom-width:2px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-moz-box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);box-shadow:0 5px 10px rgba(0, 0, 0, 0.2);-webkit-background-clip:padding-box;-moz-background-clip:padding;background-clip:padding-box;}.dropdown-menu.pull-right{right:0;left:auto;} +.dropdown-menu .divider{*width:100%;height:1px;margin:9px 1px;*margin:-5px 0 5px;overflow:hidden;background-color:#e5e5e5;border-bottom:1px solid #ffffff;} +.dropdown-menu>li>a{display:block;padding:3px 20px;clear:both;font-weight:normal;line-height:20px;color:#333333;white-space:nowrap;} +.dropdown-menu>li>a:hover,.dropdown-menu>li>a:focus,.dropdown-submenu:hover>a,.dropdown-submenu:focus>a{text-decoration:none;color:#ffffff;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} +.dropdown-menu>.active>a,.dropdown-menu>.active>a:hover,.dropdown-menu>.active>a:focus{color:#ffffff;text-decoration:none;outline:0;background-color:#0081c2;background-image:-moz-linear-gradient(top, #0088cc, #0077b3);background-image:-webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));background-image:-webkit-linear-gradient(top, #0088cc, #0077b3);background-image:-o-linear-gradient(top, #0088cc, #0077b3);background-image:linear-gradient(to bottom, #0088cc, #0077b3);background-repeat:repeat-x;filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0088cc', endColorstr='#ff0077b3', GradientType=0);} +.dropdown-menu>.disabled>a,.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{color:#999999;} +.dropdown-menu>.disabled>a:hover,.dropdown-menu>.disabled>a:focus{text-decoration:none;background-color:transparent;background-image:none;filter:progid:DXImageTransform.Microsoft.gradient(enabled = false);cursor:default;} +.open{*z-index:1000;}.open>.dropdown-menu{display:block;} +.dropdown-backdrop{position:fixed;left:0;right:0;bottom:0;top:0;z-index:990;} +.pull-right>.dropdown-menu{right:0;left:auto;} +.dropup .caret,.navbar-fixed-bottom .dropdown .caret{border-top:0;border-bottom:4px solid #000000;content:"";} +.dropup .dropdown-menu,.navbar-fixed-bottom .dropdown .dropdown-menu{top:auto;bottom:100%;margin-bottom:1px;} +.dropdown-submenu{position:relative;} +.dropdown-submenu>.dropdown-menu{top:0;left:100%;margin-top:-6px;margin-left:-1px;-webkit-border-radius:0 6px 6px 6px;-moz-border-radius:0 6px 6px 6px;border-radius:0 6px 6px 6px;} +.dropdown-submenu:hover>.dropdown-menu{display:block;} +.dropup .dropdown-submenu>.dropdown-menu{top:auto;bottom:0;margin-top:0;margin-bottom:-2px;-webkit-border-radius:5px 5px 5px 0;-moz-border-radius:5px 5px 5px 0;border-radius:5px 5px 5px 0;} +.dropdown-submenu>a:after{display:block;content:" ";float:right;width:0;height:0;border-color:transparent;border-style:solid;border-width:5px 0 5px 5px;border-left-color:#cccccc;margin-top:5px;margin-right:-10px;} +.dropdown-submenu:hover>a:after{border-left-color:#ffffff;} +.dropdown-submenu.pull-left{float:none;}.dropdown-submenu.pull-left>.dropdown-menu{left:-100%;margin-left:10px;-webkit-border-radius:6px 0 6px 6px;-moz-border-radius:6px 0 6px 6px;border-radius:6px 0 6px 6px;} +.dropdown .dropdown-menu .nav-header{padding-left:20px;padding-right:20px;} +.typeahead{z-index:1051;margin-top:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion{margin-bottom:20px;} +.accordion-group{margin-bottom:2px;border:1px solid #e5e5e5;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.accordion-heading{border-bottom:0;} +.accordion-heading .accordion-toggle{display:block;padding:8px 15px;} +.accordion-toggle{cursor:pointer;} +.accordion-inner{padding:9px 15px;border-top:1px solid #e5e5e5;} +.carousel{position:relative;margin-bottom:20px;line-height:1;} +.carousel-inner{overflow:hidden;width:100%;position:relative;} +.carousel-inner>.item{display:none;position:relative;-webkit-transition:0.6s ease-in-out left;-moz-transition:0.6s ease-in-out left;-o-transition:0.6s ease-in-out left;transition:0.6s ease-in-out left;}.carousel-inner>.item>img,.carousel-inner>.item>a>img{display:block;line-height:1;} +.carousel-inner>.active,.carousel-inner>.next,.carousel-inner>.prev{display:block;} +.carousel-inner>.active{left:0;} +.carousel-inner>.next,.carousel-inner>.prev{position:absolute;top:0;width:100%;} +.carousel-inner>.next{left:100%;} +.carousel-inner>.prev{left:-100%;} +.carousel-inner>.next.left,.carousel-inner>.prev.right{left:0;} +.carousel-inner>.active.left{left:-100%;} +.carousel-inner>.active.right{left:100%;} +.carousel-control{position:absolute;top:40%;left:15px;width:40px;height:40px;margin-top:-20px;font-size:60px;font-weight:100;line-height:30px;color:#ffffff;text-align:center;background:#222222;border:3px solid #ffffff;-webkit-border-radius:23px;-moz-border-radius:23px;border-radius:23px;opacity:0.5;filter:alpha(opacity=50);}.carousel-control.right{left:auto;right:15px;} +.carousel-control:hover,.carousel-control:focus{color:#ffffff;text-decoration:none;opacity:0.9;filter:alpha(opacity=90);} +.carousel-indicators{position:absolute;top:15px;right:15px;z-index:5;margin:0;list-style:none;}.carousel-indicators li{display:block;float:left;width:10px;height:10px;margin-left:5px;text-indent:-999px;background-color:#ccc;background-color:rgba(255, 255, 255, 0.25);border-radius:5px;} +.carousel-indicators .active{background-color:#fff;} +.carousel-caption{position:absolute;left:0;right:0;bottom:0;padding:15px;background:#333333;background:rgba(0, 0, 0, 0.75);} +.carousel-caption h4,.carousel-caption p{color:#ffffff;line-height:20px;} +.carousel-caption h4{margin:0 0 5px;} +.carousel-caption p{margin-bottom:0;} +.well{min-height:20px;padding:19px;margin-bottom:20px;background-color:#f5f5f5;border:1px solid #e3e3e3;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;-webkit-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);-moz-box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);box-shadow:inset 0 1px 1px rgba(0, 0, 0, 0.05);}.well blockquote{border-color:#ddd;border-color:rgba(0, 0, 0, 0.15);} +.well-large{padding:24px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.well-small{padding:9px;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.close{float:right;font-size:20px;font-weight:bold;line-height:20px;color:#000000;text-shadow:0 1px 0 #ffffff;opacity:0.2;filter:alpha(opacity=20);}.close:hover,.close:focus{color:#000000;text-decoration:none;cursor:pointer;opacity:0.4;filter:alpha(opacity=40);} +button.close{padding:0;cursor:pointer;background:transparent;border:0;-webkit-appearance:none;} +.pull-right{float:right;} +.pull-left{float:left;} +.hide{display:none;} +.show{display:block;} +.invisible{visibility:hidden;} +.affix{position:fixed;} +.fade{opacity:0;-webkit-transition:opacity 0.15s linear;-moz-transition:opacity 0.15s linear;-o-transition:opacity 0.15s linear;transition:opacity 0.15s linear;}.fade.in{opacity:1;} +.collapse{position:relative;height:0;overflow:hidden;-webkit-transition:height 0.35s ease;-moz-transition:height 0.35s ease;-o-transition:height 0.35s ease;transition:height 0.35s ease;}.collapse.in{height:auto;} +@-ms-viewport{width:device-width;}.hidden{display:none;visibility:hidden;} +.visible-phone{display:none !important;} +.visible-tablet{display:none !important;} +.hidden-desktop{display:none !important;} +.visible-desktop{display:inherit !important;} +@media (min-width:768px) and (max-width:979px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important ;} .visible-tablet{display:inherit !important;} .hidden-tablet{display:none !important;}}@media (max-width:767px){.hidden-desktop{display:inherit !important;} .visible-desktop{display:none !important;} .visible-phone{display:inherit !important;} .hidden-phone{display:none !important;}}.visible-print{display:none !important;} +@media print{.visible-print{display:inherit !important;} .hidden-print{display:none !important;}}@media (max-width:767px){body{padding-left:20px;padding-right:20px;} .navbar-fixed-top,.navbar-fixed-bottom,.navbar-static-top{margin-left:-20px;margin-right:-20px;} .container-fluid{padding:0;} .dl-horizontal dt{float:none;clear:none;width:auto;text-align:left;} .dl-horizontal dd{margin-left:0;} .container{width:auto;} .row-fluid{width:100%;} .row,.thumbnails{margin-left:0;} .thumbnails>li{float:none;margin-left:0;} [class*="span"],.uneditable-input[class*="span"],.row-fluid [class*="span"]{float:none;display:block;width:100%;margin-left:0;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .span12,.row-fluid .span12{width:100%;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .row-fluid [class*="offset"]:first-child{margin-left:0;} .input-large,.input-xlarge,.input-xxlarge,input[class*="span"],select[class*="span"],textarea[class*="span"],.uneditable-input{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;} .input-prepend input,.input-append input,.input-prepend input[class*="span"],.input-append input[class*="span"]{display:inline-block;width:auto;} .controls-row [class*="span"]+[class*="span"]{margin-left:0;} .modal{position:fixed;top:20px;left:20px;right:20px;width:auto;margin:0;}.modal.fade{top:-100px;} .modal.fade.in{top:20px;}}@media (max-width:480px){.nav-collapse{-webkit-transform:translate3d(0, 0, 0);} .page-header h1 small{display:block;line-height:20px;} input[type="checkbox"],input[type="radio"]{border:1px solid #ccc;} .form-horizontal .control-label{float:none;width:auto;padding-top:0;text-align:left;} .form-horizontal .controls{margin-left:0;} .form-horizontal .control-list{padding-top:0;} .form-horizontal .form-actions{padding-left:10px;padding-right:10px;} .media .pull-left,.media .pull-right{float:none;display:block;margin-bottom:10px;} .media-object{margin-right:0;margin-left:0;} .modal{top:10px;left:10px;right:10px;} .modal-header .close{padding:10px;margin:-10px;} .carousel-caption{position:static;}}@media (min-width:768px) and (max-width:979px){.row{margin-left:-20px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:20px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:724px;} .span12{width:724px;} .span11{width:662px;} .span10{width:600px;} .span9{width:538px;} .span8{width:476px;} .span7{width:414px;} .span6{width:352px;} .span5{width:290px;} .span4{width:228px;} .span3{width:166px;} .span2{width:104px;} .span1{width:42px;} .offset12{margin-left:764px;} .offset11{margin-left:702px;} .offset10{margin-left:640px;} .offset9{margin-left:578px;} .offset8{margin-left:516px;} .offset7{margin-left:454px;} .offset6{margin-left:392px;} .offset5{margin-left:330px;} .offset4{margin-left:268px;} .offset3{margin-left:206px;} .offset2{margin-left:144px;} .offset1{margin-left:82px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.7624309392265194%;*margin-left:2.709239449864817%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.7624309392265194%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.43646408839778%;*width:91.38327259903608%;} .row-fluid .span10{width:82.87292817679558%;*width:82.81973668743387%;} .row-fluid .span9{width:74.30939226519337%;*width:74.25620077583166%;} .row-fluid .span8{width:65.74585635359117%;*width:65.69266486422946%;} .row-fluid .span7{width:57.18232044198895%;*width:57.12912895262725%;} .row-fluid .span6{width:48.61878453038674%;*width:48.56559304102504%;} .row-fluid .span5{width:40.05524861878453%;*width:40.00205712942283%;} .row-fluid .span4{width:31.491712707182323%;*width:31.43852121782062%;} .row-fluid .span3{width:22.92817679558011%;*width:22.87498530621841%;} .row-fluid .span2{width:14.3646408839779%;*width:14.311449394616199%;} .row-fluid .span1{width:5.801104972375691%;*width:5.747913483013988%;} .row-fluid .offset12{margin-left:105.52486187845304%;*margin-left:105.41847889972962%;} .row-fluid .offset12:first-child{margin-left:102.76243093922652%;*margin-left:102.6560479605031%;} .row-fluid .offset11{margin-left:96.96132596685082%;*margin-left:96.8549429881274%;} .row-fluid .offset11:first-child{margin-left:94.1988950276243%;*margin-left:94.09251204890089%;} .row-fluid .offset10{margin-left:88.39779005524862%;*margin-left:88.2914070765252%;} .row-fluid .offset10:first-child{margin-left:85.6353591160221%;*margin-left:85.52897613729868%;} .row-fluid .offset9{margin-left:79.8342541436464%;*margin-left:79.72787116492299%;} .row-fluid .offset9:first-child{margin-left:77.07182320441989%;*margin-left:76.96544022569647%;} .row-fluid .offset8{margin-left:71.2707182320442%;*margin-left:71.16433525332079%;} .row-fluid .offset8:first-child{margin-left:68.50828729281768%;*margin-left:68.40190431409427%;} .row-fluid .offset7{margin-left:62.70718232044199%;*margin-left:62.600799341718584%;} .row-fluid .offset7:first-child{margin-left:59.94475138121547%;*margin-left:59.838368402492065%;} .row-fluid .offset6{margin-left:54.14364640883978%;*margin-left:54.037263430116376%;} .row-fluid .offset6:first-child{margin-left:51.38121546961326%;*margin-left:51.27483249088986%;} .row-fluid .offset5{margin-left:45.58011049723757%;*margin-left:45.47372751851417%;} .row-fluid .offset5:first-child{margin-left:42.81767955801105%;*margin-left:42.71129657928765%;} .row-fluid .offset4{margin-left:37.01657458563536%;*margin-left:36.91019160691196%;} .row-fluid .offset4:first-child{margin-left:34.25414364640884%;*margin-left:34.14776066768544%;} .row-fluid .offset3{margin-left:28.45303867403315%;*margin-left:28.346655695309746%;} .row-fluid .offset3:first-child{margin-left:25.69060773480663%;*margin-left:25.584224756083227%;} .row-fluid .offset2{margin-left:19.88950276243094%;*margin-left:19.783119783707537%;} .row-fluid .offset2:first-child{margin-left:17.12707182320442%;*margin-left:17.02068884448102%;} .row-fluid .offset1{margin-left:11.32596685082873%;*margin-left:11.219583872105325%;} .row-fluid .offset1:first-child{margin-left:8.56353591160221%;*margin-left:8.457152932878806%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:20px;} input.span12,textarea.span12,.uneditable-input.span12{width:710px;} input.span11,textarea.span11,.uneditable-input.span11{width:648px;} input.span10,textarea.span10,.uneditable-input.span10{width:586px;} input.span9,textarea.span9,.uneditable-input.span9{width:524px;} input.span8,textarea.span8,.uneditable-input.span8{width:462px;} input.span7,textarea.span7,.uneditable-input.span7{width:400px;} input.span6,textarea.span6,.uneditable-input.span6{width:338px;} input.span5,textarea.span5,.uneditable-input.span5{width:276px;} input.span4,textarea.span4,.uneditable-input.span4{width:214px;} input.span3,textarea.span3,.uneditable-input.span3{width:152px;} input.span2,textarea.span2,.uneditable-input.span2{width:90px;} input.span1,textarea.span1,.uneditable-input.span1{width:28px;}}@media (min-width:1200px){.row{margin-left:-30px;*zoom:1;}.row:before,.row:after{display:table;content:"";line-height:0;} .row:after{clear:both;} [class*="span"]{float:left;min-height:1px;margin-left:30px;} .container,.navbar-static-top .container,.navbar-fixed-top .container,.navbar-fixed-bottom .container{width:1170px;} .span12{width:1170px;} .span11{width:1070px;} .span10{width:970px;} .span9{width:870px;} .span8{width:770px;} .span7{width:670px;} .span6{width:570px;} .span5{width:470px;} .span4{width:370px;} .span3{width:270px;} .span2{width:170px;} .span1{width:70px;} .offset12{margin-left:1230px;} .offset11{margin-left:1130px;} .offset10{margin-left:1030px;} .offset9{margin-left:930px;} .offset8{margin-left:830px;} .offset7{margin-left:730px;} .offset6{margin-left:630px;} .offset5{margin-left:530px;} .offset4{margin-left:430px;} .offset3{margin-left:330px;} .offset2{margin-left:230px;} .offset1{margin-left:130px;} .row-fluid{width:100%;*zoom:1;}.row-fluid:before,.row-fluid:after{display:table;content:"";line-height:0;} .row-fluid:after{clear:both;} .row-fluid [class*="span"]{display:block;width:100%;min-height:30px;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;float:left;margin-left:2.564102564102564%;*margin-left:2.5109110747408616%;} .row-fluid [class*="span"]:first-child{margin-left:0;} .row-fluid .controls-row [class*="span"]+[class*="span"]{margin-left:2.564102564102564%;} .row-fluid .span12{width:100%;*width:99.94680851063829%;} .row-fluid .span11{width:91.45299145299145%;*width:91.39979996362975%;} .row-fluid .span10{width:82.90598290598291%;*width:82.8527914166212%;} .row-fluid .span9{width:74.35897435897436%;*width:74.30578286961266%;} .row-fluid .span8{width:65.81196581196582%;*width:65.75877432260411%;} .row-fluid .span7{width:57.26495726495726%;*width:57.21176577559556%;} .row-fluid .span6{width:48.717948717948715%;*width:48.664757228587014%;} .row-fluid .span5{width:40.17094017094017%;*width:40.11774868157847%;} .row-fluid .span4{width:31.623931623931625%;*width:31.570740134569924%;} .row-fluid .span3{width:23.076923076923077%;*width:23.023731587561375%;} .row-fluid .span2{width:14.52991452991453%;*width:14.476723040552828%;} .row-fluid .span1{width:5.982905982905983%;*width:5.929714493544281%;} .row-fluid .offset12{margin-left:105.12820512820512%;*margin-left:105.02182214948171%;} .row-fluid .offset12:first-child{margin-left:102.56410256410257%;*margin-left:102.45771958537915%;} .row-fluid .offset11{margin-left:96.58119658119658%;*margin-left:96.47481360247316%;} .row-fluid .offset11:first-child{margin-left:94.01709401709402%;*margin-left:93.91071103837061%;} .row-fluid .offset10{margin-left:88.03418803418803%;*margin-left:87.92780505546462%;} .row-fluid .offset10:first-child{margin-left:85.47008547008548%;*margin-left:85.36370249136206%;} .row-fluid .offset9{margin-left:79.48717948717949%;*margin-left:79.38079650845607%;} .row-fluid .offset9:first-child{margin-left:76.92307692307693%;*margin-left:76.81669394435352%;} .row-fluid .offset8{margin-left:70.94017094017094%;*margin-left:70.83378796144753%;} .row-fluid .offset8:first-child{margin-left:68.37606837606839%;*margin-left:68.26968539734497%;} .row-fluid .offset7{margin-left:62.393162393162385%;*margin-left:62.28677941443899%;} .row-fluid .offset7:first-child{margin-left:59.82905982905982%;*margin-left:59.72267685033642%;} .row-fluid .offset6{margin-left:53.84615384615384%;*margin-left:53.739770867430444%;} .row-fluid .offset6:first-child{margin-left:51.28205128205128%;*margin-left:51.175668303327875%;} .row-fluid .offset5{margin-left:45.299145299145295%;*margin-left:45.1927623204219%;} .row-fluid .offset5:first-child{margin-left:42.73504273504273%;*margin-left:42.62865975631933%;} .row-fluid .offset4{margin-left:36.75213675213675%;*margin-left:36.645753773413354%;} .row-fluid .offset4:first-child{margin-left:34.18803418803419%;*margin-left:34.081651209310785%;} .row-fluid .offset3{margin-left:28.205128205128204%;*margin-left:28.0987452264048%;} .row-fluid .offset3:first-child{margin-left:25.641025641025642%;*margin-left:25.53464266230224%;} .row-fluid .offset2{margin-left:19.65811965811966%;*margin-left:19.551736679396257%;} .row-fluid .offset2:first-child{margin-left:17.094017094017094%;*margin-left:16.98763411529369%;} .row-fluid .offset1{margin-left:11.11111111111111%;*margin-left:11.004728132387708%;} .row-fluid .offset1:first-child{margin-left:8.547008547008547%;*margin-left:8.440625568285142%;} input,textarea,.uneditable-input{margin-left:0;} .controls-row [class*="span"]+[class*="span"]{margin-left:30px;} input.span12,textarea.span12,.uneditable-input.span12{width:1156px;} input.span11,textarea.span11,.uneditable-input.span11{width:1056px;} input.span10,textarea.span10,.uneditable-input.span10{width:956px;} input.span9,textarea.span9,.uneditable-input.span9{width:856px;} input.span8,textarea.span8,.uneditable-input.span8{width:756px;} input.span7,textarea.span7,.uneditable-input.span7{width:656px;} input.span6,textarea.span6,.uneditable-input.span6{width:556px;} input.span5,textarea.span5,.uneditable-input.span5{width:456px;} input.span4,textarea.span4,.uneditable-input.span4{width:356px;} input.span3,textarea.span3,.uneditable-input.span3{width:256px;} input.span2,textarea.span2,.uneditable-input.span2{width:156px;} input.span1,textarea.span1,.uneditable-input.span1{width:56px;} .thumbnails{margin-left:-30px;} .thumbnails>li{margin-left:30px;} .row-fluid .thumbnails{margin-left:0;}}@media (max-width:979px){body{padding-top:0;} .navbar-fixed-top,.navbar-fixed-bottom{position:static;} .navbar-fixed-top{margin-bottom:20px;} .navbar-fixed-bottom{margin-top:20px;} .navbar-fixed-top .navbar-inner,.navbar-fixed-bottom .navbar-inner{padding:5px;} .navbar .container{width:auto;padding:0;} .navbar .brand{padding-left:10px;padding-right:10px;margin:0 0 0 -5px;} .nav-collapse{clear:both;} .nav-collapse .nav{float:none;margin:0 0 10px;} .nav-collapse .nav>li{float:none;} .nav-collapse .nav>li>a{margin-bottom:2px;} .nav-collapse .nav>.divider-vertical{display:none;} .nav-collapse .nav .nav-header{color:#777777;text-shadow:none;} .nav-collapse .nav>li>a,.nav-collapse .dropdown-menu a{padding:9px 15px;font-weight:bold;color:#777777;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} .nav-collapse .btn{padding:4px 10px 4px;font-weight:normal;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} .nav-collapse .dropdown-menu li+li a{margin-bottom:2px;} .nav-collapse .nav>li>a:hover,.nav-collapse .nav>li>a:focus,.nav-collapse .dropdown-menu a:hover,.nav-collapse .dropdown-menu a:focus{background-color:#f2f2f2;} .navbar-inverse .nav-collapse .nav>li>a,.navbar-inverse .nav-collapse .dropdown-menu a{color:#999999;} .navbar-inverse .nav-collapse .nav>li>a:hover,.navbar-inverse .nav-collapse .nav>li>a:focus,.navbar-inverse .nav-collapse .dropdown-menu a:hover,.navbar-inverse .nav-collapse .dropdown-menu a:focus{background-color:#111111;} .nav-collapse.in .btn-group{margin-top:5px;padding:0;} .nav-collapse .dropdown-menu{position:static;top:auto;left:auto;float:none;display:none;max-width:none;margin:0 15px;padding:0;background-color:transparent;border:none;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;-webkit-box-shadow:none;-moz-box-shadow:none;box-shadow:none;} .nav-collapse .open>.dropdown-menu{display:block;} .nav-collapse .dropdown-menu:before,.nav-collapse .dropdown-menu:after{display:none;} .nav-collapse .dropdown-menu .divider{display:none;} .nav-collapse .nav>li>.dropdown-menu:before,.nav-collapse .nav>li>.dropdown-menu:after{display:none;} .nav-collapse .navbar-form,.nav-collapse .navbar-search{float:none;padding:10px 15px;margin:10px 0;border-top:1px solid #f2f2f2;border-bottom:1px solid #f2f2f2;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);-moz-box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 0 rgba(255,255,255,.1), 0 1px 0 rgba(255,255,255,.1);} .navbar-inverse .nav-collapse .navbar-form,.navbar-inverse .nav-collapse .navbar-search{border-top-color:#111111;border-bottom-color:#111111;} .navbar .nav-collapse .nav.pull-right{float:none;margin-left:0;} .nav-collapse,.nav-collapse.collapse{overflow:hidden;height:0;} .navbar .btn-navbar{display:block;} .navbar-static .navbar-inner{padding-left:10px;padding-right:10px;}}@media (min-width:980px){.nav-collapse.collapse{height:auto !important;overflow:visible !important;}} diff --git a/docs/Saml2/css/font-awesome.min.css b/docs/Saml2/css/font-awesome.min.css new file mode 100644 index 00000000..866437fa --- /dev/null +++ b/docs/Saml2/css/font-awesome.min.css @@ -0,0 +1,403 @@ +@font-face{font-family:'FontAwesome';src:url('http://github.com/font/fontawesome-webfont.eot?v=3.2.1');src:url('http://github.com/font/fontawesome-webfont.eot?#iefix&v=3.2.1') format('embedded-opentype'),url('http://github.com/font/fontawesome-webfont.woff?v=3.2.1') format('woff'),url('http://github.com/font/fontawesome-webfont.ttf?v=3.2.1') format('truetype'),url('http://github.com/font/fontawesome-webfont.svg#fontawesomeregular?v=3.2.1') format('svg');font-weight:normal;font-style:normal;}[class^="icon-"],[class*=" icon-"]{font-family:FontAwesome;font-weight:normal;font-style:normal;text-decoration:inherit;-webkit-font-smoothing:antialiased;*margin-right:.3em;} +[class^="icon-"]:before,[class*=" icon-"]:before{text-decoration:inherit;display:inline-block;speak:none;} +.icon-large:before{vertical-align:-10%;font-size:1.3333333333333333em;} +a [class^="icon-"],a [class*=" icon-"]{display:inline;} +[class^="icon-"].icon-fixed-width,[class*=" icon-"].icon-fixed-width{display:inline-block;width:1.1428571428571428em;text-align:right;padding-right:0.2857142857142857em;}[class^="icon-"].icon-fixed-width.icon-large,[class*=" icon-"].icon-fixed-width.icon-large{width:1.4285714285714286em;} +.icons-ul{margin-left:2.142857142857143em;list-style-type:none;}.icons-ul>li{position:relative;} +.icons-ul .icon-li{position:absolute;left:-2.142857142857143em;width:2.142857142857143em;text-align:center;line-height:inherit;} +[class^="icon-"].hide,[class*=" icon-"].hide{display:none;} +.icon-muted{color:#eeeeee;} +.icon-light{color:#ffffff;} +.icon-dark{color:#333333;} +.icon-border{border:solid 1px #eeeeee;padding:.2em .25em .15em;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;} +.icon-2x{font-size:2em;}.icon-2x.icon-border{border-width:2px;-webkit-border-radius:4px;-moz-border-radius:4px;border-radius:4px;} +.icon-3x{font-size:3em;}.icon-3x.icon-border{border-width:3px;-webkit-border-radius:5px;-moz-border-radius:5px;border-radius:5px;} +.icon-4x{font-size:4em;}.icon-4x.icon-border{border-width:4px;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;} +.icon-5x{font-size:5em;}.icon-5x.icon-border{border-width:5px;-webkit-border-radius:7px;-moz-border-radius:7px;border-radius:7px;} +.pull-right{float:right;} +.pull-left{float:left;} +[class^="icon-"].pull-left,[class*=" icon-"].pull-left{margin-right:.3em;} +[class^="icon-"].pull-right,[class*=" icon-"].pull-right{margin-left:.3em;} +[class^="icon-"],[class*=" icon-"]{display:inline;width:auto;height:auto;line-height:normal;vertical-align:baseline;background-image:none;background-position:0% 0%;background-repeat:repeat;margin-top:0;} +.icon-white,.nav-pills>.active>a>[class^="icon-"],.nav-pills>.active>a>[class*=" icon-"],.nav-list>.active>a>[class^="icon-"],.nav-list>.active>a>[class*=" icon-"],.navbar-inverse .nav>.active>a>[class^="icon-"],.navbar-inverse .nav>.active>a>[class*=" icon-"],.dropdown-menu>li>a:hover>[class^="icon-"],.dropdown-menu>li>a:hover>[class*=" icon-"],.dropdown-menu>.active>a>[class^="icon-"],.dropdown-menu>.active>a>[class*=" icon-"],.dropdown-submenu:hover>a>[class^="icon-"],.dropdown-submenu:hover>a>[class*=" icon-"]{background-image:none;} +.btn [class^="icon-"].icon-large,.nav [class^="icon-"].icon-large,.btn [class*=" icon-"].icon-large,.nav [class*=" icon-"].icon-large{line-height:.9em;} +.btn [class^="icon-"].icon-spin,.nav [class^="icon-"].icon-spin,.btn [class*=" icon-"].icon-spin,.nav [class*=" icon-"].icon-spin{display:inline-block;} +.nav-tabs [class^="icon-"],.nav-pills [class^="icon-"],.nav-tabs [class*=" icon-"],.nav-pills [class*=" icon-"],.nav-tabs [class^="icon-"].icon-large,.nav-pills [class^="icon-"].icon-large,.nav-tabs [class*=" icon-"].icon-large,.nav-pills [class*=" icon-"].icon-large{line-height:.9em;} +.btn [class^="icon-"].pull-left.icon-2x,.btn [class*=" icon-"].pull-left.icon-2x,.btn [class^="icon-"].pull-right.icon-2x,.btn [class*=" icon-"].pull-right.icon-2x{margin-top:.18em;} +.btn [class^="icon-"].icon-spin.icon-large,.btn [class*=" icon-"].icon-spin.icon-large{line-height:.8em;} +.btn.btn-small [class^="icon-"].pull-left.icon-2x,.btn.btn-small [class*=" icon-"].pull-left.icon-2x,.btn.btn-small [class^="icon-"].pull-right.icon-2x,.btn.btn-small [class*=" icon-"].pull-right.icon-2x{margin-top:.25em;} +.btn.btn-large [class^="icon-"],.btn.btn-large [class*=" icon-"]{margin-top:0;}.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x,.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-top:.05em;} +.btn.btn-large [class^="icon-"].pull-left.icon-2x,.btn.btn-large [class*=" icon-"].pull-left.icon-2x{margin-right:.2em;} +.btn.btn-large [class^="icon-"].pull-right.icon-2x,.btn.btn-large [class*=" icon-"].pull-right.icon-2x{margin-left:.2em;} +.nav-list [class^="icon-"],.nav-list [class*=" icon-"]{line-height:inherit;} +.icon-stack{position:relative;display:inline-block;width:2em;height:2em;line-height:2em;vertical-align:-35%;}.icon-stack [class^="icon-"],.icon-stack [class*=" icon-"]{display:block;text-align:center;position:absolute;width:100%;height:100%;font-size:1em;line-height:inherit;*line-height:2em;} +.icon-stack .icon-stack-base{font-size:2em;*line-height:1em;} +.icon-spin{display:inline-block;-moz-animation:spin 2s infinite linear;-o-animation:spin 2s infinite linear;-webkit-animation:spin 2s infinite linear;animation:spin 2s infinite linear;} +a .icon-stack,a .icon-spin{display:inline-block;text-decoration:none;} +@-moz-keyframes spin{0%{-moz-transform:rotate(0deg);} 100%{-moz-transform:rotate(359deg);}}@-webkit-keyframes spin{0%{-webkit-transform:rotate(0deg);} 100%{-webkit-transform:rotate(359deg);}}@-o-keyframes spin{0%{-o-transform:rotate(0deg);} 100%{-o-transform:rotate(359deg);}}@-ms-keyframes spin{0%{-ms-transform:rotate(0deg);} 100%{-ms-transform:rotate(359deg);}}@keyframes spin{0%{transform:rotate(0deg);} 100%{transform:rotate(359deg);}}.icon-rotate-90:before{-webkit-transform:rotate(90deg);-moz-transform:rotate(90deg);-ms-transform:rotate(90deg);-o-transform:rotate(90deg);transform:rotate(90deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=1);} +.icon-rotate-180:before{-webkit-transform:rotate(180deg);-moz-transform:rotate(180deg);-ms-transform:rotate(180deg);-o-transform:rotate(180deg);transform:rotate(180deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=2);} +.icon-rotate-270:before{-webkit-transform:rotate(270deg);-moz-transform:rotate(270deg);-ms-transform:rotate(270deg);-o-transform:rotate(270deg);transform:rotate(270deg);filter:progid:DXImageTransform.Microsoft.BasicImage(rotation=3);} +.icon-flip-horizontal:before{-webkit-transform:scale(-1, 1);-moz-transform:scale(-1, 1);-ms-transform:scale(-1, 1);-o-transform:scale(-1, 1);transform:scale(-1, 1);} +.icon-flip-vertical:before{-webkit-transform:scale(1, -1);-moz-transform:scale(1, -1);-ms-transform:scale(1, -1);-o-transform:scale(1, -1);transform:scale(1, -1);} +a .icon-rotate-90:before,a .icon-rotate-180:before,a .icon-rotate-270:before,a .icon-flip-horizontal:before,a .icon-flip-vertical:before{display:inline-block;} +.icon-glass:before{content:"\f000";} +.icon-music:before{content:"\f001";} +.icon-search:before{content:"\f002";} +.icon-envelope-alt:before{content:"\f003";} +.icon-heart:before{content:"\f004";} +.icon-star:before{content:"\f005";} +.icon-star-empty:before{content:"\f006";} +.icon-user:before{content:"\f007";} +.icon-film:before{content:"\f008";} +.icon-th-large:before{content:"\f009";} +.icon-th:before{content:"\f00a";} +.icon-th-list:before{content:"\f00b";} +.icon-ok:before{content:"\f00c";} +.icon-remove:before{content:"\f00d";} +.icon-zoom-in:before{content:"\f00e";} +.icon-zoom-out:before{content:"\f010";} +.icon-power-off:before,.icon-off:before{content:"\f011";} +.icon-signal:before{content:"\f012";} +.icon-gear:before,.icon-cog:before{content:"\f013";} +.icon-trash:before{content:"\f014";} +.icon-home:before{content:"\f015";} +.icon-file-alt:before{content:"\f016";} +.icon-time:before{content:"\f017";} +.icon-road:before{content:"\f018";} +.icon-download-alt:before{content:"\f019";} +.icon-download:before{content:"\f01a";} +.icon-upload:before{content:"\f01b";} +.icon-inbox:before{content:"\f01c";} +.icon-play-circle:before{content:"\f01d";} +.icon-rotate-right:before,.icon-repeat:before{content:"\f01e";} +.icon-refresh:before{content:"\f021";} +.icon-list-alt:before{content:"\f022";} +.icon-lock:before{content:"\f023";} +.icon-flag:before{content:"\f024";} +.icon-headphones:before{content:"\f025";} +.icon-volume-off:before{content:"\f026";} +.icon-volume-down:before{content:"\f027";} +.icon-volume-up:before{content:"\f028";} +.icon-qrcode:before{content:"\f029";} +.icon-barcode:before{content:"\f02a";} +.icon-tag:before{content:"\f02b";} +.icon-tags:before{content:"\f02c";} +.icon-book:before{content:"\f02d";} +.icon-bookmark:before{content:"\f02e";} +.icon-print:before{content:"\f02f";} +.icon-camera:before{content:"\f030";} +.icon-font:before{content:"\f031";} +.icon-bold:before{content:"\f032";} +.icon-italic:before{content:"\f033";} +.icon-text-height:before{content:"\f034";} +.icon-text-width:before{content:"\f035";} +.icon-align-left:before{content:"\f036";} +.icon-align-center:before{content:"\f037";} +.icon-align-right:before{content:"\f038";} +.icon-align-justify:before{content:"\f039";} +.icon-list:before{content:"\f03a";} +.icon-indent-left:before{content:"\f03b";} +.icon-indent-right:before{content:"\f03c";} +.icon-facetime-video:before{content:"\f03d";} +.icon-picture:before{content:"\f03e";} +.icon-pencil:before{content:"\f040";} +.icon-map-marker:before{content:"\f041";} +.icon-adjust:before{content:"\f042";} +.icon-tint:before{content:"\f043";} +.icon-edit:before{content:"\f044";} +.icon-share:before{content:"\f045";} +.icon-check:before{content:"\f046";} +.icon-move:before{content:"\f047";} +.icon-step-backward:before{content:"\f048";} +.icon-fast-backward:before{content:"\f049";} +.icon-backward:before{content:"\f04a";} +.icon-play:before{content:"\f04b";} +.icon-pause:before{content:"\f04c";} +.icon-stop:before{content:"\f04d";} +.icon-forward:before{content:"\f04e";} +.icon-fast-forward:before{content:"\f050";} +.icon-step-forward:before{content:"\f051";} +.icon-eject:before{content:"\f052";} +.icon-chevron-left:before{content:"\f053";} +.icon-chevron-right:before{content:"\f054";} +.icon-plus-sign:before{content:"\f055";} +.icon-minus-sign:before{content:"\f056";} +.icon-remove-sign:before{content:"\f057";} +.icon-ok-sign:before{content:"\f058";} +.icon-question-sign:before{content:"\f059";} +.icon-info-sign:before{content:"\f05a";} +.icon-screenshot:before{content:"\f05b";} +.icon-remove-circle:before{content:"\f05c";} +.icon-ok-circle:before{content:"\f05d";} +.icon-ban-circle:before{content:"\f05e";} +.icon-arrow-left:before{content:"\f060";} +.icon-arrow-right:before{content:"\f061";} +.icon-arrow-up:before{content:"\f062";} +.icon-arrow-down:before{content:"\f063";} +.icon-mail-forward:before,.icon-share-alt:before{content:"\f064";} +.icon-resize-full:before{content:"\f065";} +.icon-resize-small:before{content:"\f066";} +.icon-plus:before{content:"\f067";} +.icon-minus:before{content:"\f068";} +.icon-asterisk:before{content:"\f069";} +.icon-exclamation-sign:before{content:"\f06a";} +.icon-gift:before{content:"\f06b";} +.icon-leaf:before{content:"\f06c";} +.icon-fire:before{content:"\f06d";} +.icon-eye-open:before{content:"\f06e";} +.icon-eye-close:before{content:"\f070";} +.icon-warning-sign:before{content:"\f071";} +.icon-plane:before{content:"\f072";} +.icon-calendar:before{content:"\f073";} +.icon-random:before{content:"\f074";} +.icon-comment:before{content:"\f075";} +.icon-magnet:before{content:"\f076";} +.icon-chevron-up:before{content:"\f077";} +.icon-chevron-down:before{content:"\f078";} +.icon-retweet:before{content:"\f079";} +.icon-shopping-cart:before{content:"\f07a";} +.icon-folder-close:before{content:"\f07b";} +.icon-folder-open:before{content:"\f07c";} +.icon-resize-vertical:before{content:"\f07d";} +.icon-resize-horizontal:before{content:"\f07e";} +.icon-bar-chart:before{content:"\f080";} +.icon-twitter-sign:before{content:"\f081";} +.icon-facebook-sign:before{content:"\f082";} +.icon-camera-retro:before{content:"\f083";} +.icon-key:before{content:"\f084";} +.icon-gears:before,.icon-cogs:before{content:"\f085";} +.icon-comments:before{content:"\f086";} +.icon-thumbs-up-alt:before{content:"\f087";} +.icon-thumbs-down-alt:before{content:"\f088";} +.icon-star-half:before{content:"\f089";} +.icon-heart-empty:before{content:"\f08a";} +.icon-signout:before{content:"\f08b";} +.icon-linkedin-sign:before{content:"\f08c";} +.icon-pushpin:before{content:"\f08d";} +.icon-external-link:before{content:"\f08e";} +.icon-signin:before{content:"\f090";} +.icon-trophy:before{content:"\f091";} +.icon-github-sign:before{content:"\f092";} +.icon-upload-alt:before{content:"\f093";} +.icon-lemon:before{content:"\f094";} +.icon-phone:before{content:"\f095";} +.icon-unchecked:before,.icon-check-empty:before{content:"\f096";} +.icon-bookmark-empty:before{content:"\f097";} +.icon-phone-sign:before{content:"\f098";} +.icon-twitter:before{content:"\f099";} +.icon-facebook:before{content:"\f09a";} +.icon-github:before{content:"\f09b";} +.icon-unlock:before{content:"\f09c";} +.icon-credit-card:before{content:"\f09d";} +.icon-rss:before{content:"\f09e";} +.icon-hdd:before{content:"\f0a0";} +.icon-bullhorn:before{content:"\f0a1";} +.icon-bell:before{content:"\f0a2";} +.icon-certificate:before{content:"\f0a3";} +.icon-hand-right:before{content:"\f0a4";} +.icon-hand-left:before{content:"\f0a5";} +.icon-hand-up:before{content:"\f0a6";} +.icon-hand-down:before{content:"\f0a7";} +.icon-circle-arrow-left:before{content:"\f0a8";} +.icon-circle-arrow-right:before{content:"\f0a9";} +.icon-circle-arrow-up:before{content:"\f0aa";} +.icon-circle-arrow-down:before{content:"\f0ab";} +.icon-globe:before{content:"\f0ac";} +.icon-wrench:before{content:"\f0ad";} +.icon-tasks:before{content:"\f0ae";} +.icon-filter:before{content:"\f0b0";} +.icon-briefcase:before{content:"\f0b1";} +.icon-fullscreen:before{content:"\f0b2";} +.icon-group:before{content:"\f0c0";} +.icon-link:before{content:"\f0c1";} +.icon-cloud:before{content:"\f0c2";} +.icon-beaker:before{content:"\f0c3";} +.icon-cut:before{content:"\f0c4";} +.icon-copy:before{content:"\f0c5";} +.icon-paperclip:before,.icon-paper-clip:before{content:"\f0c6";} +.icon-save:before{content:"\f0c7";} +.icon-sign-blank:before{content:"\f0c8";} +.icon-reorder:before{content:"\f0c9";} +.icon-list-ul:before{content:"\f0ca";} +.icon-list-ol:before{content:"\f0cb";} +.icon-strikethrough:before{content:"\f0cc";} +.icon-underline:before{content:"\f0cd";} +.icon-table:before{content:"\f0ce";} +.icon-magic:before{content:"\f0d0";} +.icon-truck:before{content:"\f0d1";} +.icon-pinterest:before{content:"\f0d2";} +.icon-pinterest-sign:before{content:"\f0d3";} +.icon-google-plus-sign:before{content:"\f0d4";} +.icon-google-plus:before{content:"\f0d5";} +.icon-money:before{content:"\f0d6";} +.icon-caret-down:before{content:"\f0d7";} +.icon-caret-up:before{content:"\f0d8";} +.icon-caret-left:before{content:"\f0d9";} +.icon-caret-right:before{content:"\f0da";} +.icon-columns:before{content:"\f0db";} +.icon-sort:before{content:"\f0dc";} +.icon-sort-down:before{content:"\f0dd";} +.icon-sort-up:before{content:"\f0de";} +.icon-envelope:before{content:"\f0e0";} +.icon-linkedin:before{content:"\f0e1";} +.icon-rotate-left:before,.icon-undo:before{content:"\f0e2";} +.icon-legal:before{content:"\f0e3";} +.icon-dashboard:before{content:"\f0e4";} +.icon-comment-alt:before{content:"\f0e5";} +.icon-comments-alt:before{content:"\f0e6";} +.icon-bolt:before{content:"\f0e7";} +.icon-sitemap:before{content:"\f0e8";} +.icon-umbrella:before{content:"\f0e9";} +.icon-paste:before{content:"\f0ea";} +.icon-lightbulb:before{content:"\f0eb";} +.icon-exchange:before{content:"\f0ec";} +.icon-cloud-download:before{content:"\f0ed";} +.icon-cloud-upload:before{content:"\f0ee";} +.icon-user-md:before{content:"\f0f0";} +.icon-stethoscope:before{content:"\f0f1";} +.icon-suitcase:before{content:"\f0f2";} +.icon-bell-alt:before{content:"\f0f3";} +.icon-coffee:before{content:"\f0f4";} +.icon-food:before{content:"\f0f5";} +.icon-file-text-alt:before{content:"\f0f6";} +.icon-building:before{content:"\f0f7";} +.icon-hospital:before{content:"\f0f8";} +.icon-ambulance:before{content:"\f0f9";} +.icon-medkit:before{content:"\f0fa";} +.icon-fighter-jet:before{content:"\f0fb";} +.icon-beer:before{content:"\f0fc";} +.icon-h-sign:before{content:"\f0fd";} +.icon-plus-sign-alt:before{content:"\f0fe";} +.icon-double-angle-left:before{content:"\f100";} +.icon-double-angle-right:before{content:"\f101";} +.icon-double-angle-up:before{content:"\f102";} +.icon-double-angle-down:before{content:"\f103";} +.icon-angle-left:before{content:"\f104";} +.icon-angle-right:before{content:"\f105";} +.icon-angle-up:before{content:"\f106";} +.icon-angle-down:before{content:"\f107";} +.icon-desktop:before{content:"\f108";} +.icon-laptop:before{content:"\f109";} +.icon-tablet:before{content:"\f10a";} +.icon-mobile-phone:before{content:"\f10b";} +.icon-circle-blank:before{content:"\f10c";} +.icon-quote-left:before{content:"\f10d";} +.icon-quote-right:before{content:"\f10e";} +.icon-spinner:before{content:"\f110";} +.icon-circle:before{content:"\f111";} +.icon-mail-reply:before,.icon-reply:before{content:"\f112";} +.icon-github-alt:before{content:"\f113";} +.icon-folder-close-alt:before{content:"\f114";} +.icon-folder-open-alt:before{content:"\f115";} +.icon-expand-alt:before{content:"\f116";} +.icon-collapse-alt:before{content:"\f117";} +.icon-smile:before{content:"\f118";} +.icon-frown:before{content:"\f119";} +.icon-meh:before{content:"\f11a";} +.icon-gamepad:before{content:"\f11b";} +.icon-keyboard:before{content:"\f11c";} +.icon-flag-alt:before{content:"\f11d";} +.icon-flag-checkered:before{content:"\f11e";} +.icon-terminal:before{content:"\f120";} +.icon-code:before{content:"\f121";} +.icon-reply-all:before{content:"\f122";} +.icon-mail-reply-all:before{content:"\f122";} +.icon-star-half-full:before,.icon-star-half-empty:before{content:"\f123";} +.icon-location-arrow:before{content:"\f124";} +.icon-crop:before{content:"\f125";} +.icon-code-fork:before{content:"\f126";} +.icon-unlink:before{content:"\f127";} +.icon-question:before{content:"\f128";} +.icon-info:before{content:"\f129";} +.icon-exclamation:before{content:"\f12a";} +.icon-superscript:before{content:"\f12b";} +.icon-subscript:before{content:"\f12c";} +.icon-eraser:before{content:"\f12d";} +.icon-puzzle-piece:before{content:"\f12e";} +.icon-microphone:before{content:"\f130";} +.icon-microphone-off:before{content:"\f131";} +.icon-shield:before{content:"\f132";} +.icon-calendar-empty:before{content:"\f133";} +.icon-fire-extinguisher:before{content:"\f134";} +.icon-rocket:before{content:"\f135";} +.icon-maxcdn:before{content:"\f136";} +.icon-chevron-sign-left:before{content:"\f137";} +.icon-chevron-sign-right:before{content:"\f138";} +.icon-chevron-sign-up:before{content:"\f139";} +.icon-chevron-sign-down:before{content:"\f13a";} +.icon-html5:before{content:"\f13b";} +.icon-css3:before{content:"\f13c";} +.icon-anchor:before{content:"\f13d";} +.icon-unlock-alt:before{content:"\f13e";} +.icon-bullseye:before{content:"\f140";} +.icon-ellipsis-horizontal:before{content:"\f141";} +.icon-ellipsis-vertical:before{content:"\f142";} +.icon-rss-sign:before{content:"\f143";} +.icon-play-sign:before{content:"\f144";} +.icon-ticket:before{content:"\f145";} +.icon-minus-sign-alt:before{content:"\f146";} +.icon-check-minus:before{content:"\f147";} +.icon-level-up:before{content:"\f148";} +.icon-level-down:before{content:"\f149";} +.icon-check-sign:before{content:"\f14a";} +.icon-edit-sign:before{content:"\f14b";} +.icon-external-link-sign:before{content:"\f14c";} +.icon-share-sign:before{content:"\f14d";} +.icon-compass:before{content:"\f14e";} +.icon-collapse:before{content:"\f150";} +.icon-collapse-top:before{content:"\f151";} +.icon-expand:before{content:"\f152";} +.icon-euro:before,.icon-eur:before{content:"\f153";} +.icon-gbp:before{content:"\f154";} +.icon-dollar:before,.icon-usd:before{content:"\f155";} +.icon-rupee:before,.icon-inr:before{content:"\f156";} +.icon-yen:before,.icon-jpy:before{content:"\f157";} +.icon-renminbi:before,.icon-cny:before{content:"\f158";} +.icon-won:before,.icon-krw:before{content:"\f159";} +.icon-bitcoin:before,.icon-btc:before{content:"\f15a";} +.icon-file:before{content:"\f15b";} +.icon-file-text:before{content:"\f15c";} +.icon-sort-by-alphabet:before{content:"\f15d";} +.icon-sort-by-alphabet-alt:before{content:"\f15e";} +.icon-sort-by-attributes:before{content:"\f160";} +.icon-sort-by-attributes-alt:before{content:"\f161";} +.icon-sort-by-order:before{content:"\f162";} +.icon-sort-by-order-alt:before{content:"\f163";} +.icon-thumbs-up:before{content:"\f164";} +.icon-thumbs-down:before{content:"\f165";} +.icon-youtube-sign:before{content:"\f166";} +.icon-youtube:before{content:"\f167";} +.icon-xing:before{content:"\f168";} +.icon-xing-sign:before{content:"\f169";} +.icon-youtube-play:before{content:"\f16a";} +.icon-dropbox:before{content:"\f16b";} +.icon-stackexchange:before{content:"\f16c";} +.icon-instagram:before{content:"\f16d";} +.icon-flickr:before{content:"\f16e";} +.icon-adn:before{content:"\f170";} +.icon-bitbucket:before{content:"\f171";} +.icon-bitbucket-sign:before{content:"\f172";} +.icon-tumblr:before{content:"\f173";} +.icon-tumblr-sign:before{content:"\f174";} +.icon-long-arrow-down:before{content:"\f175";} +.icon-long-arrow-up:before{content:"\f176";} +.icon-long-arrow-left:before{content:"\f177";} +.icon-long-arrow-right:before{content:"\f178";} +.icon-apple:before{content:"\f179";} +.icon-windows:before{content:"\f17a";} +.icon-android:before{content:"\f17b";} +.icon-linux:before{content:"\f17c";} +.icon-dribbble:before{content:"\f17d";} +.icon-skype:before{content:"\f17e";} +.icon-foursquare:before{content:"\f180";} +.icon-trello:before{content:"\f181";} +.icon-female:before{content:"\f182";} +.icon-male:before{content:"\f183";} +.icon-gittip:before{content:"\f184";} +.icon-sun:before{content:"\f185";} +.icon-moon:before{content:"\f186";} +.icon-archive:before{content:"\f187";} +.icon-bug:before{content:"\f188";} +.icon-vk:before{content:"\f189";} +.icon-weibo:before{content:"\f18a";} +.icon-renren:before{content:"\f18b";} diff --git a/docs/Saml2/css/jquery.iviewer.css b/docs/Saml2/css/jquery.iviewer.css new file mode 100644 index 00000000..11f5f094 --- /dev/null +++ b/docs/Saml2/css/jquery.iviewer.css @@ -0,0 +1,65 @@ +.viewer { + -ms-touch-action: none; +} + +.iviewer_common { + position:absolute; + bottom:10px; + border: 1px solid #000; + height: 28px; + z-index: 5000; +} + +.iviewer_cursor { + cursor: url(http://github.com/images/iviewer/hand.cur) 6 8, pointer; +} + +.iviewer_drag_cursor { + cursor: url(http://github.com/images/iviewer/grab.cur) 6 8, pointer; +} + +.iviewer_button { + width: 28px; + cursor: pointer; + background-position: center center; + background-repeat: no-repeat; +} + +.iviewer_zoom_in { + left: 20px; + background: url(http://github.com/images/iviewer/iviewer.zoom_in.png); +} + +.iviewer_zoom_out { + left: 55px; + background: url(http://github.com/images/iviewer/iviewer.zoom_out.png); +} + +.iviewer_zoom_zero { + left: 90px; + background: url(http://github.com/images/iviewer/iviewer.zoom_zero.png); +} + +.iviewer_zoom_fit { + left: 125px; + background: url(http://github.com/images/iviewer/iviewer.zoom_fit.png); +} + +.iviewer_zoom_status { + left: 160px; + font: 1em/28px Sans; + color: #000; + background-color: #fff; + text-align: center; + width: 60px; +} + +.iviewer_rotate_left { + left: 227px; + background: #fff url(http://github.com/images/iviewer/iviewer.rotate_left.png) center center no-repeat; +} + +.iviewer_rotate_right { + left: 262px; + background: #fff url(http://github.com/images/iviewer/iviewer.rotate_right.png) center center no-repeat; +} diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/Read Me.txt b/docs/Saml2/css/phpdocumentor-clean-icons/Read Me.txt new file mode 100644 index 00000000..9d2b9e57 --- /dev/null +++ b/docs/Saml2/css/phpdocumentor-clean-icons/Read Me.txt @@ -0,0 +1,3 @@ +To modify your generated font, use the *dev.svg* file, located in the *fonts* folder in this package. You can import this dev.svg file to the IcoMoon app. All the tags (class names) and the Unicode points of your glyphs are saved in this file. + +See the documentation for more info on how to use this package: http://icomoon.io/#docs/font-face \ No newline at end of file diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.dev.svg b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.dev.svg new file mode 100644 index 00000000..8b543c17 --- /dev/null +++ b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.dev.svg @@ -0,0 +1,17 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.eot b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.eot new file mode 100644 index 00000000..ef43f265 Binary files /dev/null and b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.eot differ diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.svg b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.svg new file mode 100644 index 00000000..cf0548b5 --- /dev/null +++ b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.svg @@ -0,0 +1,17 @@ + + + + +This is a custom SVG font generated by IcoMoon. + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.ttf b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.ttf new file mode 100644 index 00000000..1937c7a3 Binary files /dev/null and b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.ttf differ diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.woff b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.woff new file mode 100644 index 00000000..32fe30d4 Binary files /dev/null and b/docs/Saml2/css/phpdocumentor-clean-icons/fonts/phpdocumentor-clean-icons.woff differ diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/lte-ie7.js b/docs/Saml2/css/phpdocumentor-clean-icons/lte-ie7.js new file mode 100644 index 00000000..881c16ec --- /dev/null +++ b/docs/Saml2/css/phpdocumentor-clean-icons/lte-ie7.js @@ -0,0 +1,30 @@ +/* Load this script using conditional IE comments if you need to support IE 7 and IE 6. */ + +window.onload = function() { + function addIcon(el, entity) { + var html = el.innerHTML; + el.innerHTML = '' + entity + '' + html; + } + var icons = { + 'icon-trait' : '', + 'icon-interface' : '', + 'icon-class' : '' + }, + els = document.getElementsByTagName('*'), + i, attr, html, c, el; + for (i = 0; ; i += 1) { + el = els[i]; + if(!el) { + break; + } + attr = el.getAttribute('data-icon'); + if (attr) { + addIcon(el, attr); + } + c = el.className; + c = c.match(/icon-[^\s'"]+/); + if (c && icons[c[0]]) { + addIcon(el, icons[c[0]]); + } + } +}; \ No newline at end of file diff --git a/docs/Saml2/css/phpdocumentor-clean-icons/style.css b/docs/Saml2/css/phpdocumentor-clean-icons/style.css new file mode 100644 index 00000000..f069ec1f --- /dev/null +++ b/docs/Saml2/css/phpdocumentor-clean-icons/style.css @@ -0,0 +1,48 @@ +@font-face { + font-family: 'phpdocumentor-clean-icons'; + src:url('http://github.com/fonts/phpdocumentor-clean-icons.eot'); + src:url('http://github.com/fonts/phpdocumentor-clean-icons.eot?#iefix') format('embedded-opentype'), + url('http://github.com/fonts/phpdocumentor-clean-icons.woff') format('woff'), + url('http://github.com/fonts/phpdocumentor-clean-icons.ttf') format('truetype'), + url('http://github.com/fonts/phpdocumentor-clean-icons.svg#phpdocumentor-clean-icons') format('svg'); + font-weight: normal; + font-style: normal; +} + +/* Use the following CSS code if you want to use data attributes for inserting your icons */ +[data-icon]:before { + font-family: 'phpdocumentor-clean-icons'; + content: attr(data-icon); + speak: none; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} + +/* Use the following CSS code if you want to have a class per icon */ +/* +Instead of a list of all class selectors, +you can use the generic selector below, but it's slower: +[class*="icon-"] { +*/ +.icon-trait, .icon-interface, .icon-class { + font-family: 'phpdocumentor-clean-icons'; + speak: none; + font-style: normal; + font-weight: normal; + font-variant: normal; + text-transform: none; + line-height: 1; + -webkit-font-smoothing: antialiased; +} +.icon-trait:before { + content: "\e000"; +} +.icon-interface:before { + content: "\e001"; +} +.icon-class:before { + content: "\e002"; +} diff --git a/docs/Saml2/css/prism.css b/docs/Saml2/css/prism.css new file mode 100644 index 00000000..17876afc --- /dev/null +++ b/docs/Saml2/css/prism.css @@ -0,0 +1,204 @@ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ + +code[class*="language-"], +pre[class*="language-"] { + color: black; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', monospace; + direction: ltr; + text-align: left; + white-space: pre; + word-spacing: normal; + + -moz-tab-size: 4; + -o-tab-size: 4; + tab-size: 4; + + -webkit-hyphens: none; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: hsla(0,0%,100%,.5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + + +.token.regex, +.token.important { + color: #e90; +} + +.token.important { + font-weight: bold; +} + +.token.entity { + cursor: help; +} +pre[data-line] { + position: relative; + padding: 1em 0 1em 3em; +} + +.line-highlight { + position: absolute; + left: 0; + right: 0; + padding: inherit 0; + margin-top: 1em; /* Same as .prism’s padding-top */ + + background: hsla(24, 20%, 50%,.08); + background: -moz-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); + background: -webkit-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); + background: -o-linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); + background: linear-gradient(left, hsla(24, 20%, 50%,.1) 70%, hsla(24, 20%, 50%,0)); + + pointer-events: none; + + line-height: inherit; + white-space: pre; +} + + .line-highlight:before, + .line-highlight[data-end]:after { + content: attr(data-start); + position: absolute; + top: .4em; + left: .6em; + min-width: 1em; + padding: 0 .5em; + background-color: hsla(24, 20%, 50%,.4); + color: hsl(24, 20%, 95%); + font: bold 65%/1.5 sans-serif; + text-align: center; + vertical-align: .3em; + border-radius: 999px; + text-shadow: none; + box-shadow: 0 1px white; + } + + .line-highlight[data-end]:after { + content: attr(data-end); + top: auto; + bottom: .4em; + } +pre.line-numbers { + position: relative; + padding-left: 3.8em; + counter-reset: linenumber; +} + +pre.line-numbers > code { + position: relative; +} + +.line-numbers .line-numbers-rows { + position: absolute; + pointer-events: none; + top: 0; + font-size: 100%; + left: -3.8em; + width: 3em; /* works for line-numbers below 1000 lines */ + letter-spacing: -1px; + border-right: 1px solid #999; + + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + +} + + .line-numbers-rows > span { + pointer-events: none; + display: block; + counter-increment: linenumber; + } + + .line-numbers-rows > span:before { + content: counter(linenumber); + color: #999; + display: block; + padding-right: 0.8em; + text-align: right; + } diff --git a/docs/Saml2/css/template.css b/docs/Saml2/css/template.css new file mode 100644 index 00000000..9edf5ee1 --- /dev/null +++ b/docs/Saml2/css/template.css @@ -0,0 +1,429 @@ +@import url(https://fonts.googleapis.com/css?family=Source+Sans+Pro); +@import url('http://github.com/phpdocumentor-clean-icons/style.css'); + +body { + padding-top: 40px; + background-color: #333333; +} + +a { + color: #6495ed; +} +a.anchor { + height: 40px; + margin-top: -40px; + display: block; +} + +h1, h2, h3, h4, h5, h6, .brand { + font-family: 'Source Sans Pro', sans-serif; + font-weight: normal; + letter-spacing: 0.05em; +} + +h2, h3, .detailsbar h1 { + overflow: hidden; + white-space: nowrap; + margin: 30px 0 20px 0; +} + +h2:after, h3:after, .detailsbar h1:after { + content: ''; + display: inline-block; + vertical-align: middle; + width: 100%; + height: 2px; + margin-left: 1em; + background: silver; +} + +h3 { + margin: 10px 0 20px 0; +} + +h4 { + margin: 20px 0 10px 0; + color: gray; + font-size: 18.5px; +} + +h3.public, h3.protected, h3.private { + padding-left: 10px; + text-overflow: ellipsis; +} + +.table tr:first-of-type th, .table tr:first-of-type td { + border-top: none; +} +.detailsbar { + color: #eeeeee; + background-color: #333333; + font-size: 0.9em; + overflow: hidden; + border-left: 2px solid gray; +} + +.detailsbar h1 { + font-size: 1.5em; + margin-bottom: 20px; + margin-top: 0; +} + +.detailsbar h2 { + font-size: 1.2em; + margin: 0; + padding: 0; +} + +.detailsbar h1:after { + background: gray; +} +.detailsbar h2:after, .detailsbar h3:after { + background: transparent; +} + +.detailsbar dt { + font-variant: small-caps; + text-transform: lowercase; + font-size: 1.1em; + letter-spacing: 0.1em; + color: silver; +} + +.hierarchy div:nth-of-type(2) { margin-left: 11px; } +.hierarchy div:nth-of-type(3) { margin-left: 22px; } +.hierarchy div:nth-of-type(4) { margin-left: 33px; } +.hierarchy div:nth-of-type(5) { margin-left: 44px; } +.hierarchy div:nth-of-type(6) { margin-left: 55px; } +.hierarchy div:nth-of-type(7) { margin-left: 66px; } +.hierarchy div:nth-of-type(8) { margin-left: 77px; } +.hierarchy div:nth-of-type(9) { margin-left: 88px; } +.hierarchy div:before { + content: "\f0da"; + font-family: FontAwesome; + margin-right: 5px; +} + +.row-fluid { + background-color: white; + overflow: hidden; +} + +footer.row-fluid, footer.row-fluid * { + background-color: #333333; + color: white; +} + +footer.row-fluid { + border-top: 2px dashed #555; + margin-top: 2px; +} + +.footer-sections .span4 { + border: 2px solid #555; + text-align: center; + border-radius: 10px; + margin-top: 70px; + margin-bottom: 20px; + background: #373737; +} + +.footer-sections .span4 h1 { + background: transparent; + margin-top: -30px; + margin-bottom: 20px; + font-size: 5em; +} + +.footer-sections .span4 h1 * { + background: transparent; +} + +.footer-sections .span4 div { + border-bottom-right-radius: 6px; + border-bottom-left-radius: 6px; + padding: 10px; + min-height: 40px; +} +.footer-sections .span4 div, .footer-sections .span4 div * { + background-color: #555; +} +.footer-sections .span4 ul { + text-align: left; + list-style: none; + margin: 0; + padding: 0; +} + +.content { + background-color: white; + padding-right: 20px; +} + +.content nav { + text-align: center; + border-bottom: 1px solid silver; + margin: 5px 0 20px 0; + padding-bottom: 5px; +} + +.content > h1 { + padding-bottom: 15px; +} + +.content > h1 small { + display: block; + padding-bottom: 8px; + font-size: 0.6em; +} + +.deprecated { + text-decoration: line-through; +} + +.method { + margin-bottom: 20px; +} + +.method .signature .argument { + color: maroon; + font-weight: bold; +} + +.class #summary section.row-fluid { + overflow: hidden +} + +.class #summary .heading { + font-weight: bold; + text-align: center; +} + +.class #summary section .span4 { + padding: 3px; + overflow: hidden; + margin-bottom: -9999px; + padding-bottom: 9999px; + white-space: nowrap; + text-overflow: ellipsis; + border-left: 5px solid transparent; +} + +.class #summary section.public .span4:first-of-type:before, +.class #summary section.public .span6:first-of-type:before, +h3.public:before { + font-family: FontAwesome; + content: "\f046"; + color: green; + display: inline-block; + width: 1.2em; +} + +.class #summary section .span4:first-of-type, +.class #summary section .span6:first-of-type { + padding-left: 21px; +} +.class #summary section .span4:first-of-type:before, +.class #summary section .span6:first-of-type:before { + margin-left: -21px; +} +.class #summary section.protected .span4:first-of-type:before, +.class #summary section.protected .span6:first-of-type:before, +h3.protected:before { + font-family: FontAwesome; + content: "\f132"; + color: orange; + display: inline-block; + width: 1.2em; +} + +.class #summary section.private .span4:first-of-type:before, +.class #summary section.private .span6:first-of-type:before, +h3.private:before { + font-family: FontAwesome; + content: "\f023"; + color: red; + display: inline-block; + width: 1.2em; +} + +.class #summary section em { + font-size: 0.9em; + color: silver; +} +.class #summary .inherited { + color: gray; + font-style: italic; +} + +.accordion-group { + border: none; +} + +.accordion { + margin-bottom: 0; +} + +.accordion a:hover { + text-decoration: none; + background: #333333; + color: #eeeeee; +} + +.accordion-heading .accordion-toggle:before { + content: "\f078"; + font-family: FontAwesome; + margin-right: 5px; +} + +.accordion-heading .accordion-toggle.collapsed:before { + content: "\f054"; +} +.accordion-heading .accordion-toggle { + float: left; + width: 16px; + height: 16px; + padding: 4px 2px 4px 12px; +} +.accordion-heading a { + display: block; + padding: 4px 12px; +} + +.accordion-inner a { + display: block; + padding: 4px 12px; +} + +.accordion-inner > ul a:before { + font-family: 'phpdocumentor-clean-icons'; + content: "\e001"; + margin-right: 5px; +} + +.accordion-inner li.class a:before { + content: "\e002"; +} + +.accordion-inner li.interface a:before { + content: "\e001"; +} + +.accordion-inner li.trait a:before { + content: "\e000"; +} + +.accordion-inner { + padding: 4px 0 4px 12px; +} +.accordion-inner ul { + list-style: none; + padding: 0; + margin: 0; +} + +.row-fluid .span2 { + width: 16.5%; +} + +body .modal { + width: 90%; /* desired relative width */ + left: 5%; /* (100%-width)/2 */ + /* place center */ + margin-left:auto; + margin-right:auto; +} + +.side-nav.nav-list li a { + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} + +@media (min-width: 767px) { + .sidebar { + position: fixed; + top: 40px; + bottom: 0; + background-color: #f3f3f3; + left: 0; + border-right: 1px solid #e9e9e9; + overflow-y: scroll; + overflow-x: hidden; + padding-top: 10px; + } + + .sidebar::-webkit-scrollbar { + width: 10px; + } + + .sidebar::-webkit-scrollbar-thumb { + background: #cccccc; + background-clip: padding-box; + border: 3px solid #f3f3f3; + border-radius: 5px; + } + + .sidebar::-webkit-scrollbar-button { + display: none; + } + + .sidebar::-webkit-scrollbar-track { + background: #f3f3f3; + } +} + +@media (max-width: 979px) { + body { + padding-top: 0; + } +} + +@media (max-width: 767px) { + .class #summary .heading { + display: none; + } + + .detailsbar h1 { + display: none; + } + + body { + background-color: white; + } + + footer.row-fluid, footer.row-fluid * { + background-color: white; + } + + .footer-sections .span4 h1 { + color: #ccccd9; + margin-top: 0; + } + + .detailsbar { + background-color: white; + color: #333; + border: none; + } + + .row-fluid .span2 { + width: 100%; + } +} + +@media (min-width: 767px) { + .detailsbar { + min-height: 100%; + margin-bottom: -99999px; + padding-bottom: 99999px; + padding-left: 20px; + padding-top: 10px; + } +} + +@media (min-width: 1200px) { + .row-fluid .span2 { + width: 16.5%; + } +} diff --git a/docs/Saml2/files/Auth.html b/docs/Saml2/files/Auth.html new file mode 100644 index 00000000..2ff51c03 --- /dev/null +++ b/docs/Saml2/files/Auth.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

Auth.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_AuthMain class of PHP Toolkit
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/Auth.php.txt b/docs/Saml2/files/Auth.php.txt new file mode 100644 index 00000000..7fca3a11 --- /dev/null +++ b/docs/Saml2/files/Auth.php.txt @@ -0,0 +1,766 @@ +_settings = new OneLogin_Saml2_Settings($oldSettings, $spValidationOnly); + } + + /** + * Returns the settings info + * + * @return OneLogin_Saml2_Settings The settings data. + */ + public function getSettings() + { + return $this->_settings; + } + + /** + * Set the strict mode active/disable + * + * @param bool $value Strict parameter + * + * @throws OneLogin_Saml2_Error + */ + public function setStrict($value) + { + if (!is_bool($value)) { + throw new OneLogin_Saml2_Error( + 'Invalid value passed to setStrict()', + OneLogin_Saml2_Error::SETTINGS_INVALID_SYNTAX + ); + } + + $this->_settings->setStrict($value); + } + + /** + * Set schemas path + * + * @param string $path + * @return $this + */ + public function setSchemasPath($path) + { + $this->_paths['schemas'] = $path; + } + + /** + * Process the SAML Response sent by the IdP. + * + * @param string|null $requestId The ID of the AuthNRequest sent by this SP to the IdP + * + * @throws OneLogin_Saml2_Error + * @throws OneLogin_Saml2_ValidationError + */ + public function processResponse($requestId = null) + { + $this->_errors = array(); + $this->_errorReason = null; + if (isset($_POST['SAMLResponse'])) { + // AuthnResponse -- HTTP_POST Binding + $response = new OneLogin_Saml2_Response($this->_settings, $_POST['SAMLResponse']); + $this->_lastResponse = $response->getXMLDocument(); + + if ($response->isValid($requestId)) { + $this->_attributes = $response->getAttributes(); + $this->_attributesWithFriendlyName = $response->getAttributesWithFriendlyName(); + $this->_nameid = $response->getNameId(); + $this->_nameidFormat = $response->getNameIdFormat(); + $this->_nameidNameQualifier = $response->getNameIdNameQualifier(); + $this->_nameidSPNameQualifier = $response->getNameIdSPNameQualifier(); + $this->_authenticated = true; + $this->_sessionIndex = $response->getSessionIndex(); + $this->_sessionExpiration = $response->getSessionNotOnOrAfter(); + $this->_lastMessageId = $response->getId(); + $this->_lastAssertionId = $response->getAssertionId(); + $this->_lastAssertionNotOnOrAfter = $response->getAssertionNotOnOrAfter(); + } else { + $this->_errors[] = 'invalid_response'; + $this->_errorReason = $response->getError(); + } + } else { + $this->_errors[] = 'invalid_binding'; + throw new OneLogin_Saml2_Error( + 'SAML Response not found, Only supported HTTP_POST Binding', + OneLogin_Saml2_Error::SAML_RESPONSE_NOT_FOUND + ); + } + } + + /** + * Process the SAML Logout Response / Logout Request sent by the IdP. + * + * @param bool $keepLocalSession When false will destroy the local session, otherwise will keep it + * @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP + * @param bool $retrieveParametersFromServer True if we want to use parameters from $_SERVER to validate the signature + * @param callable $cbDeleteSession Callback to be executed to delete session + * @param bool $stay True if we want to stay (returns the url string) False to redirect + * + * @return string|null + * + * @throws OneLogin_Saml2_Error + */ + public function processSLO($keepLocalSession = false, $requestId = null, $retrieveParametersFromServer = false, $cbDeleteSession = null, $stay = false) + { + $this->_errors = array(); + $this->_errorReason = null; + if (isset($_GET['SAMLResponse'])) { + $logoutResponse = new OneLogin_Saml2_LogoutResponse($this->_settings, $_GET['SAMLResponse']); + $this->_lastResponse = $logoutResponse->getXML(); + if (!$logoutResponse->isValid($requestId, $retrieveParametersFromServer)) { + $this->_errors[] = 'invalid_logout_response'; + $this->_errorReason = $logoutResponse->getError(); + } else if ($logoutResponse->getStatus() !== OneLogin_Saml2_Constants::STATUS_SUCCESS) { + $this->_errors[] = 'logout_not_success'; + } else { + $this->_lastMessageId = $logoutResponse->id; + if (!$keepLocalSession) { + if ($cbDeleteSession === null) { + OneLogin_Saml2_Utils::deleteLocalSession(); + } else { + call_user_func($cbDeleteSession); + } + } + } + } else if (isset($_GET['SAMLRequest'])) { + $logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, $_GET['SAMLRequest']); + $this->_lastRequest = $logoutRequest->getXML(); + if (!$logoutRequest->isValid($retrieveParametersFromServer)) { + $this->_errors[] = 'invalid_logout_request'; + $this->_errorReason = $logoutRequest->getError(); + } else { + if (!$keepLocalSession) { + if ($cbDeleteSession === null) { + OneLogin_Saml2_Utils::deleteLocalSession(); + } else { + call_user_func($cbDeleteSession); + } + } + $inResponseTo = $logoutRequest->id; + $this->_lastMessageId = $logoutRequest->id; + $responseBuilder = new OneLogin_Saml2_LogoutResponse($this->_settings); + $responseBuilder->build($inResponseTo); + $this->_lastResponse = $responseBuilder->getXML(); + + $logoutResponse = $responseBuilder->getResponse(); + + $parameters = array('SAMLResponse' => $logoutResponse); + if (isset($_GET['RelayState'])) { + $parameters['RelayState'] = $_GET['RelayState']; + } + + $security = $this->_settings->getSecurityData(); + if (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned']) { + $signature = $this->buildResponseSignature($logoutResponse, isset($parameters['RelayState'])? $parameters['RelayState']: null, $security['signatureAlgorithm']); + $parameters['SigAlg'] = $security['signatureAlgorithm']; + $parameters['Signature'] = $signature; + } + + return $this->redirectTo($this->getSLOResponseUrl(), $parameters, $stay); + } + } else { + $this->_errors[] = 'invalid_binding'; + throw new OneLogin_Saml2_Error( + 'SAML LogoutRequest/LogoutResponse not found. Only supported HTTP_REDIRECT Binding', + OneLogin_Saml2_Error::SAML_LOGOUTMESSAGE_NOT_FOUND + ); + } + } + + /** + * Redirects the user to the url past by parameter + * or to the url that we defined in our SSO Request. + * + * @param string $url The target URL to redirect the user. + * @param array $parameters Extra parameters to be passed as part of the url + * @param bool $stay True if we want to stay (returns the url string) False to redirect + * + * @return string|null + * + * @throws OneLogin_Saml2_Error + */ + public function redirectTo($url = '', $parameters = array(), $stay = false) + { + assert('is_string($url)'); + assert('is_array($parameters)'); + + if (empty($url) && isset($_REQUEST['RelayState'])) { + $url = $_REQUEST['RelayState']; + } + + return OneLogin_Saml2_Utils::redirect($url, $parameters, $stay); + } + + /** + * Checks if the user is authenticated or not. + * + * @return bool True if the user is authenticated + */ + public function isAuthenticated() + { + return $this->_authenticated; + } + + /** + * Returns the set of SAML attributes. + * + * @return array Attributes of the user. + */ + public function getAttributes() + { + return $this->_attributes; + } + + /** + * Returns the set of SAML attributes indexed by FriendlyName + * + * @return array Attributes of the user. + */ + public function getAttributesWithFriendlyName() + { + return $this->_attributesWithFriendlyName; + } + + /** + * Returns the nameID + * + * @return string The nameID of the assertion + */ + public function getNameId() + { + return $this->_nameid; + } + + /** + * Returns the nameID Format + * + * @return string The nameID Format of the assertion + */ + public function getNameIdFormat() + { + return $this->_nameidFormat; + } + + /** + * Returns the nameID NameQualifier + * + * @return string The nameID NameQualifier of the assertion + */ + public function getNameIdNameQualifier() + { + return $this->_nameidNameQualifier; + } + + /** + * Returns the nameID SP NameQualifier + * + * @return string The nameID SP NameQualifier of the assertion + */ + public function getNameIdSPNameQualifier() + { + return $this->_nameidSPNameQualifier; + } + + /** + * Returns the SessionIndex + * + * @return string|null The SessionIndex of the assertion + */ + public function getSessionIndex() + { + return $this->_sessionIndex; + } + + /** + * Returns the SessionNotOnOrAfter + * + * @return int|null The SessionNotOnOrAfter of the assertion + */ + public function getSessionExpiration() + { + return $this->_sessionExpiration; + } + + /** + * Returns if there were any error + * + * @return array Errors + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Returns the reason for the last error + * + * @return string|null Error reason + */ + public function getLastErrorReason() + { + return $this->_errorReason; + } + + /** + * Returns the requested SAML attribute + * + * @param string $name The requested attribute of the user. + * + * @return array|null Requested SAML attribute ($name). + */ + public function getAttribute($name) + { + assert('is_string($name)'); + + $value = null; + if (isset($this->_attributes[$name])) { + return $this->_attributes[$name]; + } + return $value; + } + + /** + * Returns the requested SAML attribute indexed by FriendlyName + * + * @param string $friendlyName The requested attribute of the user. + * + * @return array|null Requested SAML attribute ($friendlyName). + */ + public function getAttributeWithFriendlyName($friendlyName) + { + assert('is_string($friendlyName)'); + + $value = null; + if (isset($this->_attributesWithFriendlyName[$friendlyName])) { + return $this->_attributesWithFriendlyName[$friendlyName]; + } + return $value; + } + + /** + * Initiates the SSO process. + * + * @param string|null $returnTo The target URL the user should be returned to after login. + * @param array $parameters Extra parameters to be added to the GET + * @param bool $forceAuthn When true the AuthNRequest will set the ForceAuthn='true' + * @param bool $isPassive When true the AuthNRequest will set the Ispassive='true' + * @param bool $stay True if we want to stay (returns the url string) False to redirect + * @param bool $setNameIdPolicy When true the AuthNRueqest will set a nameIdPolicy element + * @param string $nameIdValueReq Indicates to the IdP the subject that should be authenticated + * + * @return string|null If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters + * + * @throws OneLogin_Saml2_Error + */ + public function login($returnTo = null, $parameters = array(), $forceAuthn = false, $isPassive = false, $stay = false, $setNameIdPolicy = true, $nameIdValueReq = null) + { + assert('is_array($parameters)'); + + $authnRequest = new OneLogin_Saml2_AuthnRequest($this->_settings, $forceAuthn, $isPassive, $setNameIdPolicy, $nameIdValueReq); + + $this->_lastRequest = $authnRequest->getXML(); + $this->_lastRequestID = $authnRequest->getId(); + + $samlRequest = $authnRequest->getRequest(); + $parameters['SAMLRequest'] = $samlRequest; + + if (!empty($returnTo)) { + $parameters['RelayState'] = $returnTo; + } else { + $parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery(); + } + + $security = $this->_settings->getSecurityData(); + if (isset($security['authnRequestsSigned']) && $security['authnRequestsSigned']) { + $signature = $this->buildRequestSignature($samlRequest, $parameters['RelayState'], $security['signatureAlgorithm']); + $parameters['SigAlg'] = $security['signatureAlgorithm']; + $parameters['Signature'] = $signature; + } + return $this->redirectTo($this->getSSOurl(), $parameters, $stay); + } + + /** + * Initiates the SLO process. + * + * @param string|null $returnTo The target URL the user should be returned to after logout. + * @param array $parameters Extra parameters to be added to the GET + * @param string|null $nameId The NameID that will be set in the LogoutRequest. + * @param string|null $sessionIndex The SessionIndex (taken from the SAML Response in the SSO process). + * @param bool $stay True if we want to stay (returns the url string) False to redirect + * @param string|null $nameIdFormat The NameID Format will be set in the LogoutRequest. + * @param string|null $nameIdNameQualifier The NameID NameQualifier will be set in the LogoutRequest. + * + * @return string|null If $stay is True, it return a string with the SLO URL + LogoutRequest + parameters + * + * @throws OneLogin_Saml2_Error + */ + public function logout($returnTo = null, $parameters = array(), $nameId = null, $sessionIndex = null, $stay = false, $nameIdFormat = null, $nameIdNameQualifier = null, $nameIdSPNameQualifier = null) + { + assert('is_array($parameters)'); + + $sloUrl = $this->getSLOurl(); + if (empty($sloUrl)) { + throw new OneLogin_Saml2_Error( + 'The IdP does not support Single Log Out', + OneLogin_Saml2_Error::SAML_SINGLE_LOGOUT_NOT_SUPPORTED + ); + } + + if (empty($nameId) && !empty($this->_nameid)) { + $nameId = $this->_nameid; + } + if (empty($nameIdFormat) && !empty($this->_nameidFormat)) { + $nameIdFormat = $this->_nameidFormat; + } + + $logoutRequest = new OneLogin_Saml2_LogoutRequest($this->_settings, null, $nameId, $sessionIndex, $nameIdFormat, $nameIdNameQualifier, $nameIdSPNameQualifier); + + $this->_lastRequest = $logoutRequest->getXML(); + $this->_lastRequestID = $logoutRequest->id; + + $samlRequest = $logoutRequest->getRequest(); + + $parameters['SAMLRequest'] = $samlRequest; + if (!empty($returnTo)) { + $parameters['RelayState'] = $returnTo; + } else { + $parameters['RelayState'] = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery(); + } + + $security = $this->_settings->getSecurityData(); + if (isset($security['logoutRequestSigned']) && $security['logoutRequestSigned']) { + $signature = $this->buildRequestSignature($samlRequest, $parameters['RelayState'], $security['signatureAlgorithm']); + $parameters['SigAlg'] = $security['signatureAlgorithm']; + $parameters['Signature'] = $signature; + } + + return $this->redirectTo($sloUrl, $parameters, $stay); + } + + /** + * Gets the IdP SSO url. + * + * @return string The url of the IdP Single Sign On Service + */ + public function getSSOurl() + { + return $this->_settings->getIdPSSOUrl(); + } + + /** + * Gets the IdP SLO url. + * + * @return string|null The url of the IdP Single Logout Service + */ + public function getSLOurl() + { + return $this->_settings->getIdPSLOUrl(); + } + + /** + * Gets the IdP SLO response url. + * + * @return string|null The response url of the IdP Single Logout Service + */ + public function getSLOResponseUrl() + { + return $this->_settings->getIdPSLOResponseUrl(); + } + + /** + * Gets the ID of the last AuthNRequest or LogoutRequest generated by the Service Provider. + * + * @return string The ID of the Request SAML message. + */ + public function getLastRequestID() + { + return $this->_lastRequestID; + } + + /** + * Generates the Signature for a SAML Request + * + * @param string $samlRequest The SAML Request + * @param string $relayState The RelayState + * @param string $signAlgorithm Signature algorithm method + * + * @return string A base64 encoded signature + * + * @throws OneLogin_Saml2_Error + */ + public function buildRequestSignature($samlRequest, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA1) + { + return $this->buildMessageSignature($samlRequest, $relayState, $signAlgorithm, "SAMLRequest"); + } + + /** + * Generates the Signature for a SAML Response + * + * @param string $samlResponse The SAML Response + * @param string $relayState The RelayState + * @param string $signAlgorithm Signature algorithm method + * + * @return string A base64 encoded signature + * + * @throws OneLogin_Saml2_Error + */ + public function buildResponseSignature($samlResponse, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA1) + { + return $this->buildMessageSignature($samlResponse, $relayState, $signAlgorithm, "SAMLResponse"); + } + + /** + * Generates the Signature for a SAML Response + * + * @param string $samlMessage The SAML Response + * @param string $relayState The RelayState + * @param string $signAlgorithm Signature algorithm method + * @param string $type "SAMLRequest" or "SAMLResponse" + * + * @return string A base64 encoded signature + * + * @throws OneLogin_Saml2_Error + */ + private function buildMessageSignature($samlMessage, $relayState, $signAlgorithm = XMLSecurityKey::RSA_SHA256, $type = "SAMLRequest") + { + $key = $this->_settings->getSPkey(); + if (empty($key)) { + if ($type == "SAMLRequest") { + $errorMsg = "Trying to sign the SAML Request but can't load the SP private key"; + } else { + $errorMsg = "Trying to sign the SAML Response but can't load the SP private key"; + } + + throw new OneLogin_Saml2_Error($errorMsg, OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND); + } + + $objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private')); + $objKey->loadKey($key, false); + + $security = $this->_settings->getSecurityData(); + if ($security['lowercaseUrlencoding']) { + $msg = $type.'='.rawurlencode($samlMessage); + if (isset($relayState)) { + $msg .= '&RelayState='.rawurlencode($relayState); + } + $msg .= '&SigAlg=' . rawurlencode($signAlgorithm); + } else { + $msg = $type.'='.urlencode($samlMessage); + if (isset($relayState)) { + $msg .= '&RelayState='.urlencode($relayState); + } + $msg .= '&SigAlg=' . urlencode($signAlgorithm); + } + $signature = $objKey->signData($msg); + return base64_encode($signature); + } + + /** + * @return string The ID of the last message processed + */ + public function getLastMessageId() + { + return $this->_lastMessageId; + } + + /** + * @return string The ID of the last assertion processed + */ + public function getLastAssertionId() + { + return $this->_lastAssertionId; + } + + /** + * @return int The NotOnOrAfter value of the valid + * SubjectConfirmationData node (if any) + * of the last assertion processed + */ + public function getLastAssertionNotOnOrAfter() + { + return $this->_lastAssertionNotOnOrAfter; + } + + /** + * Returns the most recently-constructed/processed + * XML SAML request (AuthNRequest, LogoutRequest) + * + * @return string The Request XML + */ + public function getLastRequestXML() + { + return $this->_lastRequest; + } + + /** + * Returns the most recently-constructed/processed + * XML SAML response (SAMLResponse, LogoutResponse). + * If the SAMLResponse was encrypted, by default tries + * to return the decrypted XML. + * + * @return string|null The Response XML + */ + public function getLastResponseXML() + { + $response = null; + if (isset($this->_lastResponse)) { + if (is_string($this->_lastResponse)) { + $response = $this->_lastResponse; + } else { + $response = $this->_lastResponse->saveXML(); + } + } + + return $response; + } +} + diff --git a/docs/Saml2/files/AuthnRequest.html b/docs/Saml2/files/AuthnRequest.html new file mode 100644 index 00000000..40b82e5b --- /dev/null +++ b/docs/Saml2/files/AuthnRequest.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

AuthnRequest.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_AuthnRequestSAML 2 Authentication Request
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/AuthnRequest.php.txt b/docs/Saml2/files/AuthnRequest.php.txt new file mode 100644 index 00000000..cbd67e04 --- /dev/null +++ b/docs/Saml2/files/AuthnRequest.php.txt @@ -0,0 +1,199 @@ +_settings = $settings; + + $spData = $this->_settings->getSPData(); + $security = $this->_settings->getSecurityData(); + + $id = OneLogin_Saml2_Utils::generateUniqueID(); + $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); + + $subjectStr = ""; + if (isset($nameIdValueReq)) { + $subjectStr = << + {$nameIdValueReq} + + +SUBJECT; + } + + $nameIdPolicyStr = ''; + if ($setNameIdPolicy) { + $nameIDPolicyFormat = $spData['NameIDFormat']; + if (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted']) { + $nameIDPolicyFormat = OneLogin_Saml2_Constants::NAMEID_ENCRYPTED; + } + + $nameIdPolicyStr = << +NAMEIDPOLICY; + } + + + $providerNameStr = ''; + $organizationData = $settings->getOrganization(); + if (!empty($organizationData)) { + $langs = array_keys($organizationData); + if (in_array('en-US', $langs)) { + $lang = 'en-US'; + } else { + $lang = $langs[0]; + } + if (isset($organizationData[$lang]['displayname']) && !empty($organizationData[$lang]['displayname'])) { + $providerNameStr = << + urn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransport + +REQUESTEDAUTHN; + } else { + $requestedAuthnStr .= " \n"; + foreach ($security['requestedAuthnContext'] as $contextValue) { + $requestedAuthnStr .= " ".$contextValue."\n"; + } + $requestedAuthnStr .= ' '; + } + } + + $spEntityId = htmlspecialchars($spData['entityId'], ENT_QUOTES); + $acsUrl = htmlspecialchars($spData['assertionConsumerService']['url'], ENT_QUOTES); + $destination = $this->_settings->getIdPSSOUrl(); + $request = << + {$spEntityId}{$subjectStr}{$nameIdPolicyStr}{$requestedAuthnStr} +
+AUTHNREQUEST; + + $this->_id = $id; + $this->_authnRequest = $request; + } + + /** + * Returns deflated, base64 encoded, unsigned AuthnRequest. + * + * @param bool|null $deflate Whether or not we should 'gzdeflate' the request body before we return it. + * + * @return string + */ + public function getRequest($deflate = null) + { + $subject = $this->_authnRequest; + + if (is_null($deflate)) { + $deflate = $this->_settings->shouldCompressRequests(); + } + + if ($deflate) { + $subject = gzdeflate($this->_authnRequest); + } + + $base64Request = base64_encode($subject); + return $base64Request; + } + + /** + * Returns the AuthNRequest ID. + * + * @return string + */ + public function getId() + { + return $this->_id; + } + + /** + * Returns the XML that will be sent as part of the request + * + * @return string + */ + public function getXML() + { + return $this->_authnRequest; + } +} + diff --git a/docs/Saml2/files/Constants.html b/docs/Saml2/files/Constants.html new file mode 100644 index 00000000..d8ffef80 --- /dev/null +++ b/docs/Saml2/files/Constants.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

Constants.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_ConstantsConstants of PHP Toolkit
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/Constants.php.txt b/docs/Saml2/files/Constants.php.txt new file mode 100644 index 00000000..e0542818 --- /dev/null +++ b/docs/Saml2/files/Constants.php.txt @@ -0,0 +1,72 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

Error.php

+

+ + + + +

Classes

+ + + + + + + + + +
OneLogin_Saml2_ErrorError class of PHP Toolkit
OneLogin_Saml2_ValidationErrorThis class implements another custom Exception handler, +related to exceptions that happens during validation process.
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/Error.php.txt b/docs/Saml2/files/Error.php.txt new file mode 100644 index 00000000..f3a6fe70 --- /dev/null +++ b/docs/Saml2/files/Error.php.txt @@ -0,0 +1,122 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

IdPMetadataParser.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_IdPMetadataParserIdP Metadata Parser of PHP Toolkit
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/IdPMetadataParser.php.txt b/docs/Saml2/files/IdPMetadataParser.php.txt new file mode 100644 index 00000000..c8464b82 --- /dev/null +++ b/docs/Saml2/files/IdPMetadataParser.php.txt @@ -0,0 +1,233 @@ +getMessage()); + } + return $metadataInfo; + } + + /** + * Get IdP Metadata Info from File + * + * @param string $filepath File path + * @param string $entityId Entity Id of the desired IdP, if no + * entity Id is provided and the XML + * metadata contains more than one + * IDPSSODescriptor, the first is returned + * @param string $desiredNameIdFormat If available on IdP metadata, use that nameIdFormat + * @param string $desiredSSOBinding Parse specific binding SSO endpoint. + * @param string $desiredSLOBinding Parse specific binding SLO endpoint. + * + * @return array metadata info in php-saml settings format + */ + public static function parseFileXML($filepath, $entityId = null, $desiredNameIdFormat = null, $desiredSSOBinding = OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT, $desiredSLOBinding = OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT) + { + $metadataInfo = array(); + + try { + if (file_exists($filepath)) { + $data = file_get_contents($filepath); + $metadataInfo = self::parseXML($data, $entityId, $desiredNameIdFormat, $desiredSSOBinding, $desiredSLOBinding); + } + } catch (Exception $e) { + throw new Exception('Error on parseFileXML. '.$e->getMessage()); + } + return $metadataInfo; + } + + /** + * Get IdP Metadata Info from URL + * + * @param string $xml XML that contains IdP metadata + * @param string $entityId Entity Id of the desired IdP, if no + * entity Id is provided and the XML + * metadata contains more than one + * IDPSSODescriptor, the first is returned + * @param string $desiredNameIdFormat If available on IdP metadata, use that nameIdFormat + * @param string $desiredSSOBinding Parse specific binding SSO endpoint. + * @param string $desiredSLOBinding Parse specific binding SLO endpoint. + * + * @return array metadata info in php-saml settings format + * + * @throws Exception + */ + public static function parseXML($xml, $entityId = null, $desiredNameIdFormat = null, $desiredSSOBinding = OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT, $desiredSLOBinding = OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT) + { + $metadataInfo = array(); + + $dom = new DOMDocument(); + $dom->preserveWhiteSpace = false; + $dom->formatOutput = true; + try { + $dom = OneLogin_Saml2_Utils::loadXML($dom, $xml); + if (!$dom) { + throw new Exception('Error parsing metadata'); + } + + $customIdPStr = ''; + if (!empty($entityId)) { + $customIdPStr = '[@entityID="' . $entityId . '"]'; + } + $idpDescryptorXPath = '//md:EntityDescriptor' . $customIdPStr . '/md:IDPSSODescriptor'; + + $idpDescriptorNodes = OneLogin_Saml2_Utils::query($dom, $idpDescryptorXPath); + + if (isset($idpDescriptorNodes) && $idpDescriptorNodes->length > 0) { + $metadataInfo['idp'] = array(); + + $idpDescriptor = $idpDescriptorNodes->item(0); + + if (empty($entityId) && $idpDescriptor->parentNode->hasAttribute('entityID')) { + $entityId = $idpDescriptor->parentNode->getAttribute('entityID'); + } + + if (!empty($entityId)) { + $metadataInfo['idp']['entityId'] = $entityId; + } + + $ssoNodes = OneLogin_Saml2_Utils::query($dom, './md:SingleSignOnService[@Binding="'.$desiredSSOBinding.'"]', $idpDescriptor); + if ($ssoNodes->length < 1) { + $ssoNodes = OneLogin_Saml2_Utils::query($dom, './md:SingleSignOnService', $idpDescriptor); + } + if ($ssoNodes->length > 0) { + $metadataInfo['idp']['singleSignOnService'] = array( + 'url' => $ssoNodes->item(0)->getAttribute('Location'), + 'binding' => $ssoNodes->item(0)->getAttribute('Binding') + ); + } + + $sloNodes = OneLogin_Saml2_Utils::query($dom, './md:SingleLogoutService[@Binding="'.$desiredSLOBinding.'"]', $idpDescriptor); + if ($sloNodes->length < 1) { + $sloNodes = OneLogin_Saml2_Utils::query($dom, './md:SingleLogoutService', $idpDescriptor); + } + if ($sloNodes->length > 0) { + $metadataInfo['idp']['singleLogoutService'] = array( + 'url' => $sloNodes->item(0)->getAttribute('Location'), + 'binding' => $sloNodes->item(0)->getAttribute('Binding') + ); + + if ($sloNodes->item(0)->hasAttribute('ResponseLocation')) { + $metadataInfo['idp']['singleLogoutService']['responseUrl'] = $sloNodes->item(0)->getAttribute('ResponseLocation'); + } + } + + $keyDescriptorCertSigningNodes = OneLogin_Saml2_Utils::query($dom, './md:KeyDescriptor[not(contains(@use, "encryption"))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate', $idpDescriptor); + + $keyDescriptorCertEncryptionNodes = OneLogin_Saml2_Utils::query($dom, './md:KeyDescriptor[not(contains(@use, "signing"))]/ds:KeyInfo/ds:X509Data/ds:X509Certificate', $idpDescriptor); + + if (!empty($keyDescriptorCertSigningNodes) || !empty($keyDescriptorCertEncryptionNodes)) { + $metadataInfo['idp']['x509certMulti'] = array(); + if (!empty($keyDescriptorCertSigningNodes)) { + foreach ($keyDescriptorCertSigningNodes as $keyDescriptorCertSigningNode) { + $metadataInfo['idp']['x509certMulti']['signing'][] = OneLogin_Saml2_Utils::formatCert($keyDescriptorCertSigningNode->nodeValue, false); + } + } + if (!empty($keyDescriptorCertEncryptionNodes)) { + foreach ($keyDescriptorCertEncryptionNodes as $keyDescriptorCertEncryptionNode) { + $metadataInfo['idp']['x509certMulti']['encryption'][] = OneLogin_Saml2_Utils::formatCert($keyDescriptorCertEncryptionNode->nodeValue, false); + } + } + + $idpCertdata = $metadataInfo['idp']['x509certMulti']; + if ((count($idpCertdata) == 1 and + ((isset($idpCertdata['signing']) and count($idpCertdata['signing']) == 1) or (isset($idpCertdata['encryption']) and count($idpCertdata['encryption']) == 1))) or + ((isset($idpCertdata['signing']) && count($idpCertdata['signing']) == 1) && isset($idpCertdata['encryption']) && count($idpCertdata['encryption']) == 1 && strcmp($idpCertdata['signing'][0], $idpCertdata['encryption'][0]) == 0)) { + if (isset($metadataInfo['idp']['x509certMulti']['signing'][0])) { + $metadataInfo['idp']['x509cert'] = $metadataInfo['idp']['x509certMulti']['signing'][0]; + } else { + $metadataInfo['idp']['x509cert'] = $metadataInfo['idp']['x509certMulti']['encryption'][0]; + } + unset($metadataInfo['idp']['x509certMulti']); + } + } + + $nameIdFormatNodes = OneLogin_Saml2_Utils::query($dom, './md:NameIDFormat', $idpDescriptor); + if ($nameIdFormatNodes->length > 0) { + $metadataInfo['sp']['NameIDFormat'] = $nameIdFormatNodes->item(0)->nodeValue; + if (!empty($desiredNameIdFormat)) { + foreach ($nameIdFormatNodes as $nameIdFormatNode) { + if (strcmp($nameIdFormatNode->nodeValue, $desiredNameIdFormat) == 0) { + $metadataInfo['sp']['NameIDFormat'] = $nameIdFormatNode->nodeValue; + break; + } + } + } + } + } + } catch (Exception $e) { + throw new Exception('Error parsing metadata. '.$e->getMessage()); + } + + return $metadataInfo; + } + + /** + * Inject metadata info into php-saml settings array + * + * @param array $settings php-saml settings array + * @param array $metadataInfo array metadata info + * + * @return array settings + */ + public static function injectIntoSettings($settings, $metadataInfo) + { + if (isset($metadataInfo['idp']) && isset($settings['idp'])) { + if (isset($metadataInfo['idp']['x509certMulti']) && !empty($metadataInfo['idp']['x509certMulti']) && isset($settings['idp']['x509cert'])) { + unset($settings['idp']['x509cert']); + } + + if (isset($metadataInfo['idp']['x509cert']) && !empty($metadataInfo['idp']['x509cert']) && isset($settings['idp']['x509certMulti'])) { + unset($settings['idp']['x509certMulti']); + } + } + + return array_replace_recursive($settings, $metadataInfo); + } +} + diff --git a/docs/Saml2/files/LogoutRequest.html b/docs/Saml2/files/LogoutRequest.html new file mode 100644 index 00000000..42f0d973 --- /dev/null +++ b/docs/Saml2/files/LogoutRequest.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

LogoutRequest.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_LogoutRequestSAML 2 Logout Request
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/LogoutRequest.php.txt b/docs/Saml2/files/LogoutRequest.php.txt new file mode 100644 index 00000000..84e4485b --- /dev/null +++ b/docs/Saml2/files/LogoutRequest.php.txt @@ -0,0 +1,453 @@ +_settings = $settings; + + $baseURL = $this->_settings->getBaseURL(); + if (!empty($baseURL)) { + OneLogin_Saml2_Utils::setBaseURL($baseURL); + } + + if (!isset($request) || empty($request)) { + $spData = $this->_settings->getSPData(); + $idpData = $this->_settings->getIdPData(); + $security = $this->_settings->getSecurityData(); + + $id = OneLogin_Saml2_Utils::generateUniqueID(); + $this->id = $id; + + $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); + + $cert = null; + if (isset($security['nameIdEncrypted']) && $security['nameIdEncrypted']) { + $existsMultiX509Enc = isset($idpData['x509certMulti']) && isset($idpData['x509certMulti']['encryption']) && !empty($idpData['x509certMulti']['encryption']); + + if ($existsMultiX509Enc) { + $cert = $idpData['x509certMulti']['encryption'][0]; + } else { + $cert = $idpData['x509cert']; + } + } + + if (!empty($nameId)) { + if (empty($nameIdFormat) && + $spData['NameIDFormat'] != OneLogin_Saml2_Constants::NAMEID_UNSPECIFIED) { + $nameIdFormat = $spData['NameIDFormat']; + } + } else { + $nameId = $idpData['entityId']; + $nameIdFormat = OneLogin_Saml2_Constants::NAMEID_ENTITY; + } + + /* From saml-core-2.0-os 8.3.6, when the entity Format is used: + "The NameQualifier, SPNameQualifier, and SPProvidedID attributes MUST be omitted. + */ + if (!empty($nameIdFormat) && $nameIdFormat == OneLogin_Saml2_Constants::NAMEID_ENTITY) { + $nameIdNameQualifier = null; + $nameIdSPNameQualifier = null; + } + // NameID Format UNSPECIFIED omitted + if (!empty($nameIdFormat) && $nameIdFormat == OneLogin_Saml2_Constants::NAMEID_UNSPECIFIED) { + $nameIdFormat = null; + } + + $nameIdObj = OneLogin_Saml2_Utils::generateNameId( + $nameId, + $nameIdSPNameQualifier, + $nameIdFormat, + $cert, + $nameIdNameQualifier + ); + + $sessionIndexStr = isset($sessionIndex) ? "{$sessionIndex}" : ""; + + $spEntityId = htmlspecialchars($spData['entityId'], ENT_QUOTES); + $destination = $this->_settings->getIdPSLOUrl(); + $logoutRequest = << + {$spEntityId} + {$nameIdObj} + {$sessionIndexStr} +
+LOGOUTREQUEST; + } else { + $decoded = base64_decode($request); + // We try to inflate + $inflated = @gzinflate($decoded); + if ($inflated != false) { + $logoutRequest = $inflated; + } else { + $logoutRequest = $decoded; + } + $this->id = self::getID($logoutRequest); + } + $this->_logoutRequest = $logoutRequest; + } + + + /** + * Returns the Logout Request defated, base64encoded, unsigned + * + * @param bool|null $deflate Whether or not we should 'gzdeflate' the request body before we return it. + * + * @return string Deflated base64 encoded Logout Request + */ + public function getRequest($deflate = null) + { + $subject = $this->_logoutRequest; + + if (is_null($deflate)) { + $deflate = $this->_settings->shouldCompressRequests(); + } + + if ($deflate) { + $subject = gzdeflate($this->_logoutRequest); + } + + return base64_encode($subject); + } + + /** + * Returns the ID of the Logout Request. + * + * @param string|DOMDocument $request Logout Request Message + * + * @return string ID + * + * @throws OneLogin_Saml2_Error + */ + public static function getID($request) + { + if ($request instanceof DOMDocument) { + $dom = $request; + } else { + $dom = new DOMDocument(); + $dom = OneLogin_Saml2_Utils::loadXML($dom, $request); + + if (false === $dom) { + throw new OneLogin_Saml2_Error( + "LogoutRequest could not be processed", + OneLogin_Saml2_Error::SAML_LOGOUTREQUEST_INVALID + ); + } + } + + $id = $dom->documentElement->getAttribute('ID'); + return $id; + } + + /** + * Gets the NameID Data of the the Logout Request. + * + * @param string|DOMDocument $request Logout Request Message + * @param string|null $key The SP key + * + * @return array Name ID Data (Value, Format, NameQualifier, SPNameQualifier) + * + * @throws OneLogin_Saml2_Error + * @throws OneLogin_Saml2_ValidationError + */ + public static function getNameIdData($request, $key = null) + { + if ($request instanceof DOMDocument) { + $dom = $request; + } else { + $dom = new DOMDocument(); + $dom = OneLogin_Saml2_Utils::loadXML($dom, $request); + } + + $encryptedEntries = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:EncryptedID'); + + if ($encryptedEntries->length == 1) { + $encryptedDataNodes = $encryptedEntries->item(0)->getElementsByTagName('EncryptedData'); + $encryptedData = $encryptedDataNodes->item(0); + + if (empty($key)) { + throw new OneLogin_Saml2_Error( + "Private Key is required in order to decrypt the NameID, check settings", + OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND + ); + } + + $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'private')); + $seckey->loadKey($key); + + $nameId = OneLogin_Saml2_Utils::decryptElement($encryptedData, $seckey); + + } else { + $entries = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:NameID'); + if ($entries->length == 1) { + $nameId = $entries->item(0); + } + } + + if (!isset($nameId)) { + throw new OneLogin_Saml2_ValidationError( + "NameID not found in the Logout Request", + OneLogin_Saml2_ValidationError::NO_NAMEID + ); + } + + $nameIdData = array(); + $nameIdData['Value'] = $nameId->nodeValue; + foreach (array('Format', 'SPNameQualifier', 'NameQualifier') as $attr) { + if ($nameId->hasAttribute($attr)) { + $nameIdData[$attr] = $nameId->getAttribute($attr); + } + } + + return $nameIdData; + } + + /** + * Gets the NameID of the Logout Request. + * + * @param string|DOMDocument $request Logout Request Message + * @param string|null $key The SP key + * + * @return string Name ID Value + * + * @throws OneLogin_Saml2_Error + * @throws OneLogin_Saml2_ValidationError + */ + public static function getNameId($request, $key = null) + { + $nameId = self::getNameIdData($request, $key); + return $nameId['Value']; + } + + /** + * Gets the Issuer of the Logout Request. + * + * @param string|DOMDocument $request Logout Request Message + * + * @return string|null $issuer The Issuer + * @throws Exception + */ + public static function getIssuer($request) + { + if ($request instanceof DOMDocument) { + $dom = $request; + } else { + $dom = new DOMDocument(); + $dom = OneLogin_Saml2_Utils::loadXML($dom, $request); + } + + $issuer = null; + $issuerNodes = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/saml:Issuer'); + if ($issuerNodes->length == 1) { + $issuer = $issuerNodes->item(0)->textContent; + } + return $issuer; + } + + /** + * Gets the SessionIndexes from the Logout Request. + * Notice: Our Constructor only support 1 SessionIndex but this parser + * extracts an array of all the SessionIndex found on a + * Logout Request, that could be many. + * + * @param string|DOMDocument $request Logout Request Message + * + * @return array The SessionIndex value + * + * @throws Exception + */ + public static function getSessionIndexes($request) + { + if ($request instanceof DOMDocument) { + $dom = $request; + } else { + $dom = new DOMDocument(); + $dom = OneLogin_Saml2_Utils::loadXML($dom, $request); + } + + $sessionIndexes = array(); + $sessionIndexNodes = OneLogin_Saml2_Utils::query($dom, '/samlp:LogoutRequest/samlp:SessionIndex'); + foreach ($sessionIndexNodes as $sessionIndexNode) { + $sessionIndexes[] = $sessionIndexNode->textContent; + } + return $sessionIndexes; + } + + /** + * Checks if the Logout Request received is valid. + * + * @param bool $retrieveParametersFromServer + * + * @return bool If the Logout Request is or not valid + */ + public function isValid($retrieveParametersFromServer = false) + { + $this->_error = null; + try { + $dom = new DOMDocument(); + $dom = OneLogin_Saml2_Utils::loadXML($dom, $this->_logoutRequest); + + $idpData = $this->_settings->getIdPData(); + $idPEntityId = $idpData['entityId']; + + if ($this->_settings->isStrict()) { + $security = $this->_settings->getSecurityData(); + + if ($security['wantXMLValidation']) { + $res = OneLogin_Saml2_Utils::validateXML($dom, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); + if (!$res instanceof DOMDocument) { + throw new OneLogin_Saml2_ValidationError( + "Invalid SAML Logout Request. Not match the saml-schema-protocol-2.0.xsd", + OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT + ); + } + } + + $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery(); + + // Check NotOnOrAfter + if ($dom->documentElement->hasAttribute('NotOnOrAfter')) { + $na = OneLogin_Saml2_Utils::parseSAML2Time($dom->documentElement->getAttribute('NotOnOrAfter')); + if ($na <= time()) { + throw new OneLogin_Saml2_ValidationError( + "Could not validate timestamp: expired. Check system clock.", + OneLogin_Saml2_ValidationError::RESPONSE_EXPIRED + ); + } + } + + // Check destination + if ($dom->documentElement->hasAttribute('Destination')) { + $destination = $dom->documentElement->getAttribute('Destination'); + if (empty($destination)) { + if (!$security['relaxDestinationValidation']) { + throw new OneLogin_Saml2_ValidationError( + "The LogoutRequest has an empty Destination value", + OneLogin_Saml2_ValidationError::EMPTY_DESTINATION + ); + } + } else { + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURL); + if (strncmp($destination, $currentURL, $urlComparisonLength) !== 0) { + $currentURLNoRouted = OneLogin_Saml2_Utils::getSelfURLNoQuery(); + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURLNoRouted); + + if (strncmp($destination, $currentURLNoRouted, $urlComparisonLength) !== 0) { + throw new OneLogin_Saml2_ValidationError( + "The LogoutRequest was received at $currentURL instead of $destination", + OneLogin_Saml2_ValidationError::WRONG_DESTINATION + ); + } + } + } + } + + $nameId = static::getNameId($dom, $this->_settings->getSPkey()); + + // Check issuer + $issuer = static::getIssuer($dom); + if (!empty($issuer) && $issuer != $idPEntityId) { + throw new OneLogin_Saml2_ValidationError( + "Invalid issuer in the Logout Request", + OneLogin_Saml2_ValidationError::WRONG_ISSUER + ); + } + + if ($security['wantMessagesSigned'] && !isset($_GET['Signature'])) { + throw new OneLogin_Saml2_ValidationError( + "The Message of the Logout Request is not signed and the SP require it", + OneLogin_Saml2_ValidationError::NO_SIGNED_MESSAGE + ); + } + } + + if (isset($_GET['Signature'])) { + $signatureValid = OneLogin_Saml2_Utils::validateBinarySign("SAMLRequest", $_GET, $idpData, $retrieveParametersFromServer); + if (!$signatureValid) { + throw new OneLogin_Saml2_ValidationError( + "Signature validation failed. Logout Request rejected", + OneLogin_Saml2_ValidationError::INVALID_SIGNATURE + ); + } + } + + return true; + } catch (Exception $e) { + $this->_error = $e->getMessage(); + $debug = $this->_settings->isDebugActive(); + if ($debug) { + echo htmlentities($this->_error); + } + return false; + } + } + + /** + * After execute a validation process, if fails this method returns the cause + * + * @return string Cause + */ + public function getError() + { + return $this->_error; + } + + /** + * Returns the XML that will be sent as part of the request + * or that was received at the SP + * + * @return string + */ + public function getXML() + { + return $this->_logoutRequest; + } +} + diff --git a/docs/Saml2/files/LogoutResponse.html b/docs/Saml2/files/LogoutResponse.html new file mode 100644 index 00000000..b9edd4ec --- /dev/null +++ b/docs/Saml2/files/LogoutResponse.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

LogoutResponse.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_LogoutResponseSAML 2 Logout Response
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/LogoutResponse.php.txt b/docs/Saml2/files/LogoutResponse.php.txt new file mode 100644 index 00000000..68d6da84 --- /dev/null +++ b/docs/Saml2/files/LogoutResponse.php.txt @@ -0,0 +1,312 @@ +_settings = $settings; + + $baseURL = $this->_settings->getBaseURL(); + if (!empty($baseURL)) { + OneLogin_Saml2_Utils::setBaseURL($baseURL); + } + + if ($response) { + $decoded = base64_decode($response); + $inflated = @gzinflate($decoded); + if ($inflated != false) { + $this->_logoutResponse = $inflated; + } else { + $this->_logoutResponse = $decoded; + } + $this->document = new DOMDocument(); + $this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->_logoutResponse); + + if (false === $this->document) { + throw new OneLogin_Saml2_Error( + "LogoutResponse could not be processed", + OneLogin_Saml2_Error::SAML_LOGOUTRESPONSE_INVALID + ); + } + + if ($this->document->documentElement->hasAttribute('ID')) { + $this->id = $this->document->documentElement->getAttribute('ID'); + } + } + } + + /** + * Gets the Issuer of the Logout Response. + * + * @return string|null $issuer The Issuer + */ + public function getIssuer() + { + $issuer = null; + $issuerNodes = $this->_query('/samlp:LogoutResponse/saml:Issuer'); + if ($issuerNodes->length == 1) { + $issuer = $issuerNodes->item(0)->textContent; + } + return $issuer; + } + + /** + * Gets the Status of the Logout Response. + * + * @return string|null The Status + */ + public function getStatus() + { + $entries = $this->_query('/samlp:LogoutResponse/samlp:Status/samlp:StatusCode'); + if ($entries->length != 1) { + return null; + } + $status = $entries->item(0)->getAttribute('Value'); + return $status; + } + + /** + * Determines if the SAML LogoutResponse is valid + * + * @param string|null $requestId The ID of the LogoutRequest sent by this SP to the IdP + * @param bool $retrieveParametersFromServer + * + * @return bool Returns if the SAML LogoutResponse is or not valid + */ + public function isValid($requestId = null, $retrieveParametersFromServer = false) + { + $this->_error = null; + try { + $idpData = $this->_settings->getIdPData(); + $idPEntityId = $idpData['entityId']; + + if ($this->_settings->isStrict()) { + $security = $this->_settings->getSecurityData(); + + if ($security['wantXMLValidation']) { + $res = OneLogin_Saml2_Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); + if (!$res instanceof DOMDocument) { + throw new OneLogin_Saml2_ValidationError( + "Invalid SAML Logout Response. Not match the saml-schema-protocol-2.0.xsd", + OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT + ); + } + } + + // Check if the InResponseTo of the Logout Response matchs the ID of the Logout Request (requestId) if provided + if (isset($requestId) && $this->document->documentElement->hasAttribute('InResponseTo')) { + $inResponseTo = $this->document->documentElement->getAttribute('InResponseTo'); + if ($requestId != $inResponseTo) { + throw new OneLogin_Saml2_ValidationError( + "The InResponseTo of the Logout Response: $inResponseTo, does not match the ID of the Logout request sent by the SP: $requestId", + OneLogin_Saml2_ValidationError::WRONG_INRESPONSETO + ); + } + } + + // Check issuer + $issuer = $this->getIssuer(); + if (!empty($issuer) && $issuer != $idPEntityId) { + throw new OneLogin_Saml2_ValidationError( + "Invalid issuer in the Logout Response", + OneLogin_Saml2_ValidationError::WRONG_ISSUER + ); + } + + $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery(); + + // Check destination + if ($this->document->documentElement->hasAttribute('Destination')) { + $destination = $this->document->documentElement->getAttribute('Destination'); + if (empty($destination)) { + if (!$security['relaxDestinationValidation']) { + throw new OneLogin_Saml2_ValidationError( + "The LogoutResponse has an empty Destination value", + OneLogin_Saml2_ValidationError::EMPTY_DESTINATION + ); + } + } else { + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURL); + if (strncmp($destination, $currentURL, $urlComparisonLength) !== 0) { + $currentURLNoRouted = OneLogin_Saml2_Utils::getSelfURLNoQuery(); + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURLNoRouted); + + if (strncmp($destination, $currentURLNoRouted, $urlComparisonLength) !== 0) { + throw new OneLogin_Saml2_ValidationError( + "The LogoutResponse was received at $currentURL instead of $destination", + OneLogin_Saml2_ValidationError::WRONG_DESTINATION + ); + } + } + } + } + + if ($security['wantMessagesSigned'] && !isset($_GET['Signature'])) { + throw new OneLogin_Saml2_ValidationError( + "The Message of the Logout Response is not signed and the SP requires it", + OneLogin_Saml2_ValidationError::NO_SIGNED_MESSAGE + ); + } + } + + if (isset($_GET['Signature'])) { + $signatureValid = OneLogin_Saml2_Utils::validateBinarySign("SAMLResponse", $_GET, $idpData, $retrieveParametersFromServer); + if (!$signatureValid) { + throw new OneLogin_Saml2_ValidationError( + "Signature validation failed. Logout Response rejected", + OneLogin_Saml2_ValidationError::INVALID_SIGNATURE + ); + } + } + return true; + } catch (Exception $e) { + $this->_error = $e->getMessage(); + $debug = $this->_settings->isDebugActive(); + if ($debug) { + echo htmlentities($this->_error); + } + return false; + } + } + + /** + * Extracts a node from the DOMDocument (Logout Response Menssage) + * + * @param string $query Xpath Expresion + * + * @return DOMNodeList The queried node + */ + private function _query($query) + { + return OneLogin_Saml2_Utils::query($this->document, $query); + + } + + /** + * Generates a Logout Response object. + * + * @param string $inResponseTo InResponseTo value for the Logout Response. + */ + public function build($inResponseTo) + { + + $spData = $this->_settings->getSPData(); + $idpData = $this->_settings->getIdPData(); + + $this->id = OneLogin_Saml2_Utils::generateUniqueID(); + $issueInstant = OneLogin_Saml2_Utils::parseTime2SAML(time()); + + $spEntityId = htmlspecialchars($spData['entityId'], ENT_QUOTES); + $destination = $this->_settings->getIdPSLOResponseUrl(); + $logoutResponse = << + {$spEntityId} + + + +
+LOGOUTRESPONSE; + $this->_logoutResponse = $logoutResponse; + } + + /** + * Returns a Logout Response object. + * + * @param bool|null $deflate Whether or not we should 'gzdeflate' the response body before we return it. + * + * @return string Logout Response deflated and base64 encoded + */ + public function getResponse($deflate = null) + { + $subject = $this->_logoutResponse; + + if (is_null($deflate)) { + $deflate = $this->_settings->shouldCompressResponses(); + } + + if ($deflate) { + $subject = gzdeflate($this->_logoutResponse); + } + return base64_encode($subject); + } + + /** + * After execute a validation process, if fails this method returns the cause. + * + * @return string Cause + */ + public function getError() + { + return $this->_error; + } + + /** + * @return string the ID of the Response + */ + public function getId() + { + return $this->id; + } + + /** + * Returns the XML that will be sent as part of the response + * or that was received at the SP + * + * @return string + */ + public function getXML() + { + return $this->_logoutResponse; + } +} + diff --git a/docs/Saml2/files/Metadata.html b/docs/Saml2/files/Metadata.html new file mode 100644 index 00000000..92dbf0bb --- /dev/null +++ b/docs/Saml2/files/Metadata.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

Metadata.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_MetadataMetadata lib of PHP Toolkit
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/Metadata.php.txt b/docs/Saml2/files/Metadata.php.txt new file mode 100644 index 00000000..4a1a79fc --- /dev/null +++ b/docs/Saml2/files/Metadata.php.txt @@ -0,0 +1,249 @@ + + +SLS_TEMPLATE; + } + + if ($authnsign) { + $strAuthnsign = 'true'; + } else { + $strAuthnsign = 'false'; + } + + if ($wsign) { + $strWsign = 'true'; + } else { + $strWsign = 'false'; + } + + $strOrganization = ''; + + if (!empty($organization)) { + $organizationInfoNames = array(); + $organizationInfoDisplaynames = array(); + $organizationInfoUrls = array(); + foreach ($organization as $lang => $info) { + $organizationInfoNames[] = <<{$info['name']} +ORGANIZATION_NAME; + $organizationInfoDisplaynames[] = <<{$info['displayname']} +ORGANIZATION_DISPLAY; + $organizationInfoUrls[] = <<{$info['url']} +ORGANIZATION_URL; + } + $orgData = implode("\n", $organizationInfoNames)."\n".implode("\n", $organizationInfoDisplaynames)."\n".implode("\n", $organizationInfoUrls); + $strOrganization = << +{$orgData} + +ORGANIZATIONSTR; + } + + $strContacts = ''; + if (!empty($contacts)) { + $contactsInfo = array(); + foreach ($contacts as $type => $info) { + $contactsInfo[] = << + {$info['givenName']} + {$info['emailAddress']} + +CONTACT; + } + $strContacts = "\n".implode("\n", $contactsInfo); + } + + $strAttributeConsumingService = ''; + if (isset($sp['attributeConsumingService'])) { + $attrCsDesc = ''; + if (isset($sp['attributeConsumingService']['serviceDescription'])) { + $attrCsDesc = sprintf( + ' %s' . PHP_EOL, + $sp['attributeConsumingService']['serviceDescription'] + ); + } + if (!isset($sp['attributeConsumingService']['serviceName'])) { + $sp['attributeConsumingService']['serviceName'] = 'Service'; + } + $requestedAttributeData = array(); + foreach ($sp['attributeConsumingService']['requestedAttributes'] as $attribute) { + $requestedAttributeStr = sprintf(' {$attrValue} +ATTRIBUTEVALUE; + } + $reqAttrAuxStr .= "\n "; + } + + $requestedAttributeData[] = $requestedAttributeStr . $reqAttrAuxStr; + } + + $requestedAttributeStr = implode(PHP_EOL, $requestedAttributeData); + $strAttributeConsumingService = << + {$sp['attributeConsumingService']['serviceName']} +{$attrCsDesc}{$requestedAttributeStr} + +METADATA_TEMPLATE; + } + + $spEntityId = htmlspecialchars($sp['entityId'], ENT_QUOTES); + $acsUrl = htmlspecialchars($sp['assertionConsumerService']['url'], ENT_QUOTES); + $metadata = << + + +{$sls} {$sp['NameIDFormat']} + + {$strAttributeConsumingService} + {$strOrganization}{$strContacts} + +METADATA_TEMPLATE; + return $metadata; + } + + /** + * Signs the metadata with the key/cert provided + * + * @param string $metadata SAML Metadata XML + * @param string $key x509 key + * @param string $cert x509 cert + * @param string $signAlgorithm Signature algorithm method + * @param string $digestAlgorithm Digest algorithm method + * + * @return string Signed Metadata + * + * @throws Exception + */ + public static function signMetadata($metadata, $key, $cert, $signAlgorithm = XMLSecurityKey::RSA_SHA1, $digestAlgorithm = XMLSecurityDSig::SHA1) + { + return OneLogin_Saml2_Utils::addSign($metadata, $key, $cert, $signAlgorithm, $digestAlgorithm); + } + + /** + * Adds the x509 descriptors (sign/encriptation) to the metadata + * The same cert will be used for sign/encrypt + * + * @param string $metadata SAML Metadata XML + * @param string $cert x509 cert + * @param bool $wantsEncrypted Whether to include the KeyDescriptor for encryption + * + * @return string Metadata with KeyDescriptors + * + * @throws Exception + */ + public static function addX509KeyDescriptors($metadata, $cert, $wantsEncrypted = true) + { + $xml = new DOMDocument(); + $xml->preserveWhiteSpace = false; + $xml->formatOutput = true; + try { + $xml = OneLogin_Saml2_Utils::loadXML($xml, $metadata); + if (!$xml) { + throw new Exception('Error parsing metadata'); + } + } catch (Exception $e) { + throw new Exception('Error parsing metadata. '.$e->getMessage()); + } + + $formatedCert = OneLogin_Saml2_Utils::formatCert($cert, false); + $x509Certificate = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'X509Certificate', $formatedCert); + + $keyData = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:X509Data'); + $keyData->appendChild($x509Certificate); + + $keyInfo = $xml->createElementNS(OneLogin_Saml2_Constants::NS_DS, 'ds:KeyInfo'); + $keyInfo->appendChild($keyData); + + $keyDescriptor = $xml->createElementNS(OneLogin_Saml2_Constants::NS_MD, "md:KeyDescriptor"); + + $SPSSODescriptor = $xml->getElementsByTagName('SPSSODescriptor')->item(0); + $SPSSODescriptor->insertBefore($keyDescriptor->cloneNode(), $SPSSODescriptor->firstChild); + if ($wantsEncrypted === true) { + $SPSSODescriptor->insertBefore($keyDescriptor->cloneNode(), $SPSSODescriptor->firstChild); + } + + $signing = $xml->getElementsByTagName('KeyDescriptor')->item(0); + $signing->setAttribute('use', 'signing'); + $signing->appendChild($keyInfo); + + if ($wantsEncrypted === true) { + $encryption = $xml->getElementsByTagName('KeyDescriptor')->item(1); + $encryption->setAttribute('use', 'encryption'); + + $encryption->appendChild($keyInfo->cloneNode(true)); + } + + return $xml->saveXML(); + } +} + diff --git a/docs/Saml2/files/Response.html b/docs/Saml2/files/Response.html new file mode 100644 index 00000000..169842dc --- /dev/null +++ b/docs/Saml2/files/Response.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

Response.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_ResponseSAML 2 Authentication Response
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/Response.php.txt b/docs/Saml2/files/Response.php.txt new file mode 100644 index 00000000..eb22b241 --- /dev/null +++ b/docs/Saml2/files/Response.php.txt @@ -0,0 +1,1198 @@ +_settings = $settings; + + $baseURL = $this->_settings->getBaseURL(); + if (!empty($baseURL)) { + OneLogin_Saml2_Utils::setBaseURL($baseURL); + } + + $this->response = base64_decode($response); + + $this->document = new DOMDocument(); + $this->document = OneLogin_Saml2_Utils::loadXML($this->document, $this->response); + if (!$this->document) { + throw new OneLogin_Saml2_ValidationError( + "SAML Response could not be processed", + OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT + ); + } + + // Quick check for the presence of EncryptedAssertion + $encryptedAssertionNodes = $this->document->getElementsByTagName('EncryptedAssertion'); + if ($encryptedAssertionNodes->length !== 0) { + $this->decryptedDocument = clone $this->document; + $this->encrypted = true; + $this->decryptedDocument = $this->_decryptAssertion($this->decryptedDocument); + } + } + + /** + * Determines if the SAML Response is valid using the certificate. + * + * @param string|null $requestId The ID of the AuthNRequest sent by this SP to the IdP + * + * @return bool Validate the document + */ + public function isValid($requestId = null) + { + $this->_error = null; + try { + // Check SAML version + if ($this->document->documentElement->getAttribute('Version') != '2.0') { + throw new OneLogin_Saml2_ValidationError( + "Unsupported SAML version", + OneLogin_Saml2_ValidationError::UNSUPPORTED_SAML_VERSION + ); + } + + if (!$this->document->documentElement->hasAttribute('ID')) { + throw new OneLogin_Saml2_ValidationError( + "Missing ID attribute on SAML Response", + OneLogin_Saml2_ValidationError::MISSING_ID + ); + } + + $this->checkStatus(); + + $singleAssertion = $this->validateNumAssertions(); + if (!$singleAssertion) { + throw new OneLogin_Saml2_ValidationError( + "SAML Response must contain 1 assertion", + OneLogin_Saml2_ValidationError::WRONG_NUMBER_OF_ASSERTIONS + ); + } + + $idpData = $this->_settings->getIdPData(); + $idPEntityId = $idpData['entityId']; + $spData = $this->_settings->getSPData(); + $spEntityId = $spData['entityId']; + + $signedElements = $this->processSignedElements(); + + $responseTag = '{'.OneLogin_Saml2_Constants::NS_SAMLP.'}Response'; + $assertionTag = '{'.OneLogin_Saml2_Constants::NS_SAML.'}Assertion'; + + $hasSignedResponse = in_array($responseTag, $signedElements); + $hasSignedAssertion = in_array($assertionTag, $signedElements); + + if ($this->_settings->isStrict()) { + $security = $this->_settings->getSecurityData(); + + if ($security['wantXMLValidation']) { + $errorXmlMsg = "Invalid SAML Response. Not match the saml-schema-protocol-2.0.xsd"; + $res = OneLogin_Saml2_Utils::validateXML($this->document, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); + if (!$res instanceof DOMDocument) { + throw new OneLogin_Saml2_ValidationError( + $errorXmlMsg, + OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT + ); + } + + # If encrypted, check also the decrypted document + if ($this->encrypted) { + $res = OneLogin_Saml2_Utils::validateXML($this->decryptedDocument, 'saml-schema-protocol-2.0.xsd', $this->_settings->isDebugActive(), $this->_settings->getSchemasPath()); + if (!$res instanceof DOMDocument) { + throw new OneLogin_Saml2_ValidationError( + $errorXmlMsg, + OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT + ); + } + } + + } + + $currentURL = OneLogin_Saml2_Utils::getSelfRoutedURLNoQuery(); + + $responseInResponseTo = null; + if ($this->document->documentElement->hasAttribute('InResponseTo')) { + $responseInResponseTo = $this->document->documentElement->getAttribute('InResponseTo'); + } + + if (!isset($requestId) && isset($responseInResponseTo) && $security['rejectUnsolicitedResponsesWithInResponseTo']) { + throw new OneLogin_Saml2_ValidationError( + "The Response has an InResponseTo attribute: " . $responseInResponseTo . " while no InResponseTo was expected", + OneLogin_Saml2_ValidationError::WRONG_INRESPONSETO + ); + } + + // Check if the InResponseTo of the Response matchs the ID of the AuthNRequest (requestId) if provided + if (isset($requestId) && $requestId != $responseInResponseTo) { + if ($responseInResponseTo == null) { + throw new OneLogin_Saml2_ValidationError( + "No InResponseTo at the Response, but it was provided the requestId related to the AuthNRequest sent by the SP: $requestId", + OneLogin_Saml2_ValidationError::WRONG_INRESPONSETO + ); + } else { + throw new OneLogin_Saml2_ValidationError( + "The InResponseTo of the Response: $responseInResponseTo, does not match the ID of the AuthNRequest sent by the SP: $requestId", + OneLogin_Saml2_ValidationError::WRONG_INRESPONSETO + ); + } + } + + if (!$this->encrypted && $security['wantAssertionsEncrypted']) { + throw new OneLogin_Saml2_ValidationError( + "The assertion of the Response is not encrypted and the SP requires it", + OneLogin_Saml2_ValidationError::NO_ENCRYPTED_ASSERTION + ); + } + + if ($security['wantNameIdEncrypted']) { + $encryptedIdNodes = $this->_queryAssertion('/saml:Subject/saml:EncryptedID/xenc:EncryptedData'); + if ($encryptedIdNodes->length != 1) { + throw new OneLogin_Saml2_ValidationError( + "The NameID of the Response is not encrypted and the SP requires it", + OneLogin_Saml2_ValidationError::NO_ENCRYPTED_NAMEID + ); + } + } + + // Validate Conditions element exists + if (!$this->checkOneCondition()) { + throw new OneLogin_Saml2_ValidationError( + "The Assertion must include a Conditions element", + OneLogin_Saml2_ValidationError::MISSING_CONDITIONS + ); + } + + // Validate Asserion timestamps + $this->validateTimestamps(); + + // Validate AuthnStatement element exists and is unique + if (!$this->checkOneAuthnStatement()) { + throw new OneLogin_Saml2_ValidationError( + "The Assertion must include an AuthnStatement element", + OneLogin_Saml2_ValidationError::WRONG_NUMBER_OF_AUTHSTATEMENTS + ); + } + + // EncryptedAttributes are not supported + $encryptedAttributeNodes = $this->_queryAssertion('/saml:AttributeStatement/saml:EncryptedAttribute'); + if ($encryptedAttributeNodes->length > 0) { + throw new OneLogin_Saml2_ValidationError( + "There is an EncryptedAttribute in the Response and this SP not support them", + OneLogin_Saml2_ValidationError::ENCRYPTED_ATTRIBUTES + ); + } + + // Check destination + if ($this->document->documentElement->hasAttribute('Destination')) { + $destination = trim($this->document->documentElement->getAttribute('Destination')); + if (empty($destination)) { + if (!$security['relaxDestinationValidation']) { + throw new OneLogin_Saml2_ValidationError( + "The response has an empty Destination value", + OneLogin_Saml2_ValidationError::EMPTY_DESTINATION + ); + } + } else { + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURL); + if (strncmp($destination, $currentURL, $urlComparisonLength) !== 0) { + $currentURLNoRouted = OneLogin_Saml2_Utils::getSelfURLNoQuery(); + $urlComparisonLength = $security['destinationStrictlyMatches'] ? strlen($destination) : strlen($currentURLNoRouted); + + if (strncmp($destination, $currentURLNoRouted, $urlComparisonLength) !== 0) { + throw new OneLogin_Saml2_ValidationError( + "The response was received at $currentURL instead of $destination", + OneLogin_Saml2_ValidationError::WRONG_DESTINATION + ); + } + } + } + } + + // Check audience + $validAudiences = $this->getAudiences(); + if (!empty($validAudiences) && !in_array($spEntityId, $validAudiences, true)) { + throw new OneLogin_Saml2_ValidationError( + sprintf( + "Invalid audience for this Response (expected '%s', got '%s')", + $spEntityId, + implode(',', $validAudiences) + ), + OneLogin_Saml2_ValidationError::WRONG_AUDIENCE + ); + } + + // Check the issuers + $issuers = $this->getIssuers(); + foreach ($issuers as $issuer) { + $trimmedIssuer = trim($issuer); + if (empty($trimmedIssuer) || $trimmedIssuer !== $idPEntityId) { + throw new OneLogin_Saml2_ValidationError( + "Invalid issuer in the Assertion/Response (expected '$idPEntityId', got '$trimmedIssuer')", + OneLogin_Saml2_ValidationError::WRONG_ISSUER + ); + } + } + + // Check the session Expiration + $sessionExpiration = $this->getSessionNotOnOrAfter(); + if (!empty($sessionExpiration) && $sessionExpiration + OneLogin_Saml2_Constants::ALLOWED_CLOCK_DRIFT <= time()) { + throw new OneLogin_Saml2_ValidationError( + "The attributes have expired, based on the SessionNotOnOrAfter of the AttributeStatement of this Response", + OneLogin_Saml2_ValidationError::SESSION_EXPIRED + ); + } + + // Check the SubjectConfirmation, at least one SubjectConfirmation must be valid + $anySubjectConfirmation = false; + $subjectConfirmationNodes = $this->_queryAssertion('/saml:Subject/saml:SubjectConfirmation'); + foreach ($subjectConfirmationNodes as $scn) { + if ($scn->hasAttribute('Method') && $scn->getAttribute('Method') != OneLogin_Saml2_Constants::CM_BEARER) { + continue; + } + $subjectConfirmationDataNodes = $scn->getElementsByTagName('SubjectConfirmationData'); + if ($subjectConfirmationDataNodes->length == 0) { + continue; + } else { + $scnData = $subjectConfirmationDataNodes->item(0); + if ($scnData->hasAttribute('InResponseTo')) { + $inResponseTo = $scnData->getAttribute('InResponseTo'); + if (isset($responseInResponseTo) && $responseInResponseTo != $inResponseTo) { + continue; + } + } + if ($scnData->hasAttribute('Recipient')) { + $recipient = $scnData->getAttribute('Recipient'); + if (!empty($recipient) && strpos($recipient, $currentURL) === false) { + continue; + } + } + if ($scnData->hasAttribute('NotOnOrAfter')) { + $noa = OneLogin_Saml2_Utils::parseSAML2Time($scnData->getAttribute('NotOnOrAfter')); + if ($noa + OneLogin_Saml2_Constants::ALLOWED_CLOCK_DRIFT <= time()) { + continue; + } + } + if ($scnData->hasAttribute('NotBefore')) { + $nb = OneLogin_Saml2_Utils::parseSAML2Time($scnData->getAttribute('NotBefore')); + if ($nb > time() + OneLogin_Saml2_Constants::ALLOWED_CLOCK_DRIFT) { + continue; + } + } + + // Save NotOnOrAfter value + if ($scnData->hasAttribute('NotOnOrAfter')) { + $this->_validSCDNotOnOrAfter = $noa; + } + $anySubjectConfirmation = true; + break; + } + } + + if (!$anySubjectConfirmation) { + throw new OneLogin_Saml2_ValidationError( + "A valid SubjectConfirmation was not found on this Response", + OneLogin_Saml2_ValidationError::WRONG_SUBJECTCONFIRMATION + ); + } + + if ($security['wantAssertionsSigned'] && !$hasSignedAssertion) { + throw new OneLogin_Saml2_ValidationError( + "The Assertion of the Response is not signed and the SP requires it", + OneLogin_Saml2_ValidationError::NO_SIGNED_ASSERTION + ); + } + + if ($security['wantMessagesSigned'] && !$hasSignedResponse) { + throw new OneLogin_Saml2_ValidationError( + "The Message of the Response is not signed and the SP requires it", + OneLogin_Saml2_ValidationError::NO_SIGNED_MESSAGE + ); + } + } + + // Detect case not supported + if ($this->encrypted) { + $encryptedIDNodes = OneLogin_Saml2_Utils::query($this->decryptedDocument, '/samlp:Response/saml:Assertion/saml:Subject/saml:EncryptedID'); + if ($encryptedIDNodes->length > 0) { + throw new OneLogin_Saml2_ValidationError( + 'SAML Response that contains a an encrypted Assertion with encrypted nameId is not supported.', + OneLogin_Saml2_ValidationError::NOT_SUPPORTED + ); + } + } + + if (empty($signedElements) || (!$hasSignedResponse && !$hasSignedAssertion)) { + throw new OneLogin_Saml2_ValidationError( + 'No Signature found. SAML Response rejected', + OneLogin_Saml2_ValidationError::NO_SIGNATURE_FOUND + ); + } else { + $cert = $idpData['x509cert']; + $fingerprint = $idpData['certFingerprint']; + $fingerprintalg = $idpData['certFingerprintAlgorithm']; + + $multiCerts = null; + $existsMultiX509Sign = isset($idpData['x509certMulti']) && isset($idpData['x509certMulti']['signing']) && !empty($idpData['x509certMulti']['signing']); + + if ($existsMultiX509Sign) { + $multiCerts = $idpData['x509certMulti']['signing']; + } + + # If find a Signature on the Response, validates it checking the original response + if ($hasSignedResponse && !OneLogin_Saml2_Utils::validateSign($this->document, $cert, $fingerprint, $fingerprintalg, OneLogin_Saml2_Utils::RESPONSE_SIGNATURE_XPATH, $multiCerts)) { + throw new OneLogin_Saml2_ValidationError( + "Signature validation failed. SAML Response rejected", + OneLogin_Saml2_ValidationError::INVALID_SIGNATURE + ); + } + + # If find a Signature on the Assertion (decrypted assertion if was encrypted) + $documentToCheckAssertion = $this->encrypted ? $this->decryptedDocument : $this->document; + if ($hasSignedAssertion && !OneLogin_Saml2_Utils::validateSign($documentToCheckAssertion, $cert, $fingerprint, $fingerprintalg, OneLogin_Saml2_Utils::ASSERTION_SIGNATURE_XPATH, $multiCerts)) { + throw new OneLogin_Saml2_ValidationError( + "Signature validation failed. SAML Response rejected", + OneLogin_Saml2_ValidationError::INVALID_SIGNATURE + ); + } + } + return true; + } catch (Exception $e) { + $this->_error = $e->getMessage(); + $debug = $this->_settings->isDebugActive(); + if ($debug) { + echo htmlentities($this->_error); + } + return false; + } + } + + /** + * @return string|null the ID of the Response + */ + public function getId() + { + $id = null; + if ($this->document->documentElement->hasAttribute('ID')) { + $id = $this->document->documentElement->getAttribute('ID'); + } + return $id; + } + + /** + * @return string|null the ID of the assertion in the Response + * + * @throws InvalidArgumentException + */ + public function getAssertionId() + { + if (!$this->validateNumAssertions()) { + throw new InvalidArgumentException("SAML Response must contain 1 Assertion."); + } + $assertionNodes = $this->_queryAssertion(""); + $id = null; + if ($assertionNodes->length == 1 && $assertionNodes->item(0)->hasAttribute('ID')) { + $id = $assertionNodes->item(0)->getAttribute('ID'); + } + return $id; + } + + /** + * @return int the NotOnOrAfter value of the valid SubjectConfirmationData + * node if any + */ + public function getAssertionNotOnOrAfter() + { + return $this->_validSCDNotOnOrAfter; + } + + /** + * Checks if the Status is success + * + * @throws OneLogin_Saml2_ValidationError If status is not success + */ + public function checkStatus() + { + $status = OneLogin_Saml2_Utils::getStatus($this->document); + + if (isset($status['code']) && $status['code'] !== OneLogin_Saml2_Constants::STATUS_SUCCESS) { + $explodedCode = explode(':', $status['code']); + $printableCode = array_pop($explodedCode); + + $statusExceptionMsg = 'The status code of the Response was not Success, was '.$printableCode; + if (!empty($status['msg'])) { + $statusExceptionMsg .= ' -> '.$status['msg']; + } + throw new OneLogin_Saml2_ValidationError( + $statusExceptionMsg, + OneLogin_Saml2_ValidationError::STATUS_CODE_IS_NOT_SUCCESS + ); + } + } + + /** + * Checks that the samlp:Response/saml:Assertion/saml:Conditions element exists and is unique. + * + * @return boolean true if the Conditions element exists and is unique + */ + public function checkOneCondition() + { + $entries = $this->_queryAssertion("/saml:Conditions"); + if ($entries->length == 1) { + return true; + } else { + return false; + } + } + + /** + * Checks that the samlp:Response/saml:Assertion/saml:AuthnStatement element exists and is unique. + * + * @return boolean true if the AuthnStatement element exists and is unique + */ + public function checkOneAuthnStatement() + { + $entries = $this->_queryAssertion("/saml:AuthnStatement"); + if ($entries->length == 1) { + return true; + } else { + return false; + } + } + + /** + * Gets the audiences. + * + * @return array @audience The valid audiences of the response + */ + public function getAudiences() + { + $audiences = array(); + + $entries = $this->_queryAssertion('/saml:Conditions/saml:AudienceRestriction/saml:Audience'); + foreach ($entries as $entry) { + $value = trim($entry->textContent); + if (!empty($value)) { + $audiences[] = $value; + } + } + + return array_unique($audiences); + } + + /** + * Gets the Issuers (from Response and Assertion). + * + * @return array @issuers The issuers of the assertion/response + * + * @throws OneLogin_Saml2_ValidationError + */ + public function getIssuers() + { + $issuers = array(); + + $responseIssuer = OneLogin_Saml2_Utils::query($this->document, '/samlp:Response/saml:Issuer'); + if ($responseIssuer->length > 0) { + if ($responseIssuer->length == 1) { + $issuers[] = $responseIssuer->item(0)->textContent; + } else { + throw new OneLogin_Saml2_ValidationError( + "Issuer of the Response is multiple.", + OneLogin_Saml2_ValidationError::ISSUER_MULTIPLE_IN_RESPONSE + ); + } + } + + $assertionIssuer = $this->_queryAssertion('/saml:Issuer'); + if ($assertionIssuer->length == 1) { + $issuers[] = $assertionIssuer->item(0)->textContent; + } else { + throw new OneLogin_Saml2_ValidationError( + "Issuer of the Assertion not found or multiple.", + OneLogin_Saml2_ValidationError::ISSUER_NOT_FOUND_IN_ASSERTION + ); + } + + return array_unique($issuers); + } + + /** + * Gets the NameID Data provided by the SAML response from the IdP. + * + * @return array Name ID Data (Value, Format, NameQualifier, SPNameQualifier) + * + * @throws OneLogin_Saml2_ValidationError + */ + public function getNameIdData() + { + $encryptedIdDataEntries = $this->_queryAssertion('/saml:Subject/saml:EncryptedID/xenc:EncryptedData'); + + if ($encryptedIdDataEntries->length == 1) { + $encryptedData = $encryptedIdDataEntries->item(0); + + $key = $this->_settings->getSPkey(); + $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'private')); + $seckey->loadKey($key); + + $nameId = OneLogin_Saml2_Utils::decryptElement($encryptedData, $seckey); + + } else { + $entries = $this->_queryAssertion('/saml:Subject/saml:NameID'); + if ($entries->length == 1) { + $nameId = $entries->item(0); + } + } + + $nameIdData = array(); + + if (!isset($nameId)) { + $security = $this->_settings->getSecurityData(); + if ($security['wantNameId']) { + throw new OneLogin_Saml2_ValidationError( + "NameID not found in the assertion of the Response", + OneLogin_Saml2_ValidationError::NO_NAMEID + ); + } + } else { + if ($this->_settings->isStrict() && empty($nameId->nodeValue)) { + throw new OneLogin_Saml2_ValidationError( + "An empty NameID value found", + OneLogin_Saml2_ValidationError::EMPTY_NAMEID + ); + } + $nameIdData['Value'] = $nameId->nodeValue; + + foreach (array('Format', 'SPNameQualifier', 'NameQualifier') as $attr) { + if ($nameId->hasAttribute($attr)) { + if ($this->_settings->isStrict() && $attr == 'SPNameQualifier') { + $spData = $this->_settings->getSPData(); + $spEntityId = $spData['entityId']; + if ($spEntityId != $nameId->getAttribute($attr)) { + throw new OneLogin_Saml2_ValidationError( + "The SPNameQualifier value mismatch the SP entityID value.", + OneLogin_Saml2_ValidationError::SP_NAME_QUALIFIER_NAME_MISMATCH + ); + } + } + $nameIdData[$attr] = $nameId->getAttribute($attr); + } + } + } + + return $nameIdData; + } + + /** + * Gets the NameID provided by the SAML response from the IdP. + * + * @return string|null Name ID Value + * + * @throws OneLogin_Saml2_ValidationError + */ + public function getNameId() + { + $nameIdvalue = null; + $nameIdData = $this->getNameIdData(); + if (!empty($nameIdData) && isset($nameIdData['Value'])) { + $nameIdvalue = $nameIdData['Value']; + } + return $nameIdvalue; + } + + /** + * Gets the NameID Format provided by the SAML response from the IdP. + * + * @return string|null Name ID Format + * + * @throws OneLogin_Saml2_ValidationError + */ + public function getNameIdFormat() + { + $nameIdFormat = null; + $nameIdData = $this->getNameIdData(); + if (!empty($nameIdData) && isset($nameIdData['Format'])) { + $nameIdFormat = $nameIdData['Format']; + } + return $nameIdFormat; + } + + /** + * Gets the NameID NameQualifier provided by the SAML response from the IdP. + * + * @return string|null Name ID NameQualifier + * + * @throws OneLogin_Saml2_ValidationError + */ + public function getNameIdNameQualifier() + { + $nameIdNameQualifier = null; + $nameIdData = $this->getNameIdData(); + if (!empty($nameIdData) && isset($nameIdData['NameQualifier'])) { + $nameIdNameQualifier = $nameIdData['NameQualifier']; + } + return $nameIdNameQualifier; + } + + /** + * Gets the NameID SP NameQualifier provided by the SAML response from the IdP. + * + * @return string|null NameID SP NameQualifier + * + * @throws ValidationError + */ + public function getNameIdSPNameQualifier() + { + $nameIdSPNameQualifier = null; + $nameIdData = $this->getNameIdData(); + if (!empty($nameIdData) && isset($nameIdData['SPNameQualifier'])) { + $nameIdSPNameQualifier = $nameIdData['SPNameQualifier']; + } + return $nameIdSPNameQualifier; + } + + /** + * Gets the SessionNotOnOrAfter from the AuthnStatement. + * Could be used to set the local session expiration + * + * @return int|null The SessionNotOnOrAfter value + * + * @throws Exception + */ + public function getSessionNotOnOrAfter() + { + $notOnOrAfter = null; + $entries = $this->_queryAssertion('/saml:AuthnStatement[@SessionNotOnOrAfter]'); + if ($entries->length !== 0) { + $notOnOrAfter = OneLogin_Saml2_Utils::parseSAML2Time($entries->item(0)->getAttribute('SessionNotOnOrAfter')); + } + return $notOnOrAfter; + } + + /** + * Gets the SessionIndex from the AuthnStatement. + * Could be used to be stored in the local session in order + * to be used in a future Logout Request that the SP could + * send to the SP, to set what specific session must be deleted + * + * @return string|null The SessionIndex value + */ + + public function getSessionIndex() + { + $sessionIndex = null; + $entries = $this->_queryAssertion('/saml:AuthnStatement[@SessionIndex]'); + if ($entries->length !== 0) { + $sessionIndex = $entries->item(0)->getAttribute('SessionIndex'); + } + return $sessionIndex; + } + + /** + * Gets the Attributes from the AttributeStatement element. + * + * @return array The attributes of the SAML Assertion + * + * @throws OneLogin_Saml2_ValidationError + */ + public function getAttributes() + { + return $this->_getAttributesByKeyName('Name'); + } + + /** + * Gets the Attributes from the AttributeStatement element using their FriendlyName. + * + * @return array The attributes of the SAML Assertion + * + * @throws OneLogin_Saml2_ValidationError + */ + public function getAttributesWithFriendlyName() + { + return $this->_getAttributesByKeyName('FriendlyName'); + } + + /** + * @param string $keyName + * + * @return array + * + * @throws OneLogin_Saml2_ValidationError + */ + private function _getAttributesByKeyName($keyName = "Name") + { + $attributes = array(); + + $entries = $this->_queryAssertion('/saml:AttributeStatement/saml:Attribute'); + + $security = $this->_settings->getSecurityData(); + $allowRepeatAttributeName = $security['allowRepeatAttributeName']; + + /** @var $entry DOMNode */ + foreach ($entries as $entry) { + $attributeKeyNode = $entry->attributes->getNamedItem($keyName); + + if ($attributeKeyNode === null) { + continue; + } + + $attributeKeyName = $attributeKeyNode->nodeValue; + + if (in_array($attributeKeyName, array_keys($attributes), true)) { + if (!$allowRepeatAttributeName) { + throw new OneLogin_Saml2_ValidationError( + "Found an Attribute element with duplicated ".$keyName, + OneLogin_Saml2_ValidationError::DUPLICATED_ATTRIBUTE_NAME_FOUND + ); + } + } + + $attributeValues = array(); + foreach ($entry->childNodes as $childNode) { + $tagName = ($childNode->prefix ? $childNode->prefix.':' : '') . 'AttributeValue'; + if ($childNode->nodeType == XML_ELEMENT_NODE && $childNode->tagName === $tagName) { + $attributeValues[] = $childNode->nodeValue; + } + } + + if (in_array($attributeKeyName, array_keys($attributes), true)) { + $attributes[$attributeKeyName] = array_merge($attributes[$attributeKeyName], $attributeValues); + } else { + $attributes[$attributeKeyName] = $attributeValues; + } + } + return $attributes; + } + + /** + * Verifies that the document only contains a single Assertion (encrypted or not). + * + * @return bool TRUE if the document passes. + */ + public function validateNumAssertions() + { + $encryptedAssertionNodes = $this->document->getElementsByTagName('EncryptedAssertion'); + $assertionNodes = $this->document->getElementsByTagName('Assertion'); + + $valid = $assertionNodes->length + $encryptedAssertionNodes->length == 1; + + if ($this->encrypted) { + $assertionNodes = $this->decryptedDocument->getElementsByTagName('Assertion'); + $valid = $valid && $assertionNodes->length == 1; + } + + return $valid; + } + + /** + * Verifies the signature nodes: + * - Checks that are Response or Assertion + * - Check that IDs and reference URI are unique and consistent. + * + * @return array Signed element tags + * + * @throws OneLogin_Saml2_ValidationError + */ + public function processSignedElements() + { + $signedElements = array(); + $verifiedSeis = array(); + $verifiedIds = array(); + + if ($this->encrypted) { + $signNodes = $this->decryptedDocument->getElementsByTagName('Signature'); + } else { + $signNodes = $this->document->getElementsByTagName('Signature'); + } + foreach ($signNodes as $signNode) { + $responseTag = '{'.OneLogin_Saml2_Constants::NS_SAMLP.'}Response'; + $assertionTag = '{'.OneLogin_Saml2_Constants::NS_SAML.'}Assertion'; + + $signedElement = '{'.$signNode->parentNode->namespaceURI.'}'.$signNode->parentNode->localName; + + if ($signedElement != $responseTag && $signedElement != $assertionTag) { + throw new OneLogin_Saml2_ValidationError( + "Invalid Signature Element $signedElement SAML Response rejected", + OneLogin_Saml2_ValidationError::WRONG_SIGNED_ELEMENT + ); + } + + # Check that reference URI matches the parent ID and no duplicate References or IDs + $idValue = $signNode->parentNode->getAttribute('ID'); + if (empty($idValue)) { + throw new OneLogin_Saml2_ValidationError( + 'Signed Element must contain an ID. SAML Response rejected', + OneLogin_Saml2_ValidationError::ID_NOT_FOUND_IN_SIGNED_ELEMENT + ); + } + + if (in_array($idValue, $verifiedIds)) { + throw new OneLogin_Saml2_ValidationError( + 'Duplicated ID. SAML Response rejected', + OneLogin_Saml2_ValidationError::DUPLICATED_ID_IN_SIGNED_ELEMENTS + ); + } + $verifiedIds[] = $idValue; + + $ref = $signNode->getElementsByTagName('Reference'); + if ($ref->length == 1) { + $ref = $ref->item(0); + $sei = $ref->getAttribute('URI'); + if (!empty($sei)) { + $sei = substr($sei, 1); + + if ($sei != $idValue) { + throw new OneLogin_Saml2_ValidationError( + 'Found an invalid Signed Element. SAML Response rejected', + OneLogin_Saml2_ValidationError::INVALID_SIGNED_ELEMENT + ); + } + + if (in_array($sei, $verifiedSeis)) { + throw new OneLogin_Saml2_ValidationError( + 'Duplicated Reference URI. SAML Response rejected', + OneLogin_Saml2_ValidationError::DUPLICATED_REFERENCE_IN_SIGNED_ELEMENTS + ); + } + $verifiedSeis[] = $sei; + } + } else { + throw new OneLogin_Saml2_ValidationError( + 'Unexpected number of Reference nodes found for signature. SAML Response rejected.', + OneLogin_Saml2_ValidationError::UNEXPECTED_REFERENCE + ); + } + $signedElements[] = $signedElement; + } + + // Check SignedElements + if (!empty($signedElements) && !$this->validateSignedElements($signedElements)) { + throw new OneLogin_Saml2_ValidationError( + 'Found an unexpected Signature Element. SAML Response rejected', + OneLogin_Saml2_ValidationError::UNEXPECTED_SIGNED_ELEMENTS + ); + } + return $signedElements; + } + + /** + * Verifies that the document is still valid according Conditions Element. + * + * @return bool + * + * @throws Exception + * @throws OneLogin_Saml2_ValidationError + */ + public function validateTimestamps() + { + if ($this->encrypted) { + $document = $this->decryptedDocument; + } else { + $document = $this->document; + } + + $timestampNodes = $document->getElementsByTagName('Conditions'); + for ($i = 0; $i < $timestampNodes->length; $i++) { + $nbAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotBefore"); + $naAttribute = $timestampNodes->item($i)->attributes->getNamedItem("NotOnOrAfter"); + if ($nbAttribute && OneLogin_Saml2_Utils::parseSAML2Time($nbAttribute->textContent) > time() + OneLogin_Saml2_Constants::ALLOWED_CLOCK_DRIFT) { + throw new OneLogin_Saml2_ValidationError( + 'Could not validate timestamp: not yet valid. Check system clock.', + OneLogin_Saml2_ValidationError::ASSERTION_TOO_EARLY + ); + } + if ($naAttribute && OneLogin_Saml2_Utils::parseSAML2Time($naAttribute->textContent) + OneLogin_Saml2_Constants::ALLOWED_CLOCK_DRIFT <= time()) { + throw new OneLogin_Saml2_ValidationError( + 'Could not validate timestamp: expired. Check system clock.', + OneLogin_Saml2_ValidationError::ASSERTION_EXPIRED + ); + } + } + return true; + } + + /** + * Verifies that the document has the expected signed nodes. + * + * @param $signedElements + * + * @return bool + * + * @throws OneLogin_Saml2_ValidationError + */ + public function validateSignedElements($signedElements) + { + if (count($signedElements) > 2) { + return false; + } + + $responseTag = '{'.OneLogin_Saml2_Constants::NS_SAMLP.'}Response'; + $assertionTag = '{'.OneLogin_Saml2_Constants::NS_SAML.'}Assertion'; + + $ocurrence = array_count_values($signedElements); + if ((in_array($responseTag, $signedElements) && $ocurrence[$responseTag] > 1) || + (in_array($assertionTag, $signedElements) && $ocurrence[$assertionTag] > 1) || + !in_array($responseTag, $signedElements) && !in_array($assertionTag, $signedElements) + ) { + return false; + } + + // Check that the signed elements found here, are the ones that will be verified + // by OneLogin_Saml2_Utils->validateSign() + if (in_array($responseTag, $signedElements)) { + $expectedSignatureNodes = OneLogin_Saml2_Utils::query($this->document, OneLogin_Saml2_Utils::RESPONSE_SIGNATURE_XPATH); + if ($expectedSignatureNodes->length != 1) { + throw new OneLogin_Saml2_ValidationError( + "Unexpected number of Response signatures found. SAML Response rejected.", + OneLogin_Saml2_ValidationError::WRONG_NUMBER_OF_SIGNATURES_IN_RESPONSE + ); + } + } + + if (in_array($assertionTag, $signedElements)) { + $expectedSignatureNodes = $this->_query(OneLogin_Saml2_Utils::ASSERTION_SIGNATURE_XPATH); + if ($expectedSignatureNodes->length != 1) { + throw new OneLogin_Saml2_ValidationError( + "Unexpected number of Assertion signatures found. SAML Response rejected.", + OneLogin_Saml2_ValidationError::WRONG_NUMBER_OF_SIGNATURES_IN_ASSERTION + ); + } + } + + return true; + } + + /** + * Extracts a node from the DOMDocument (Assertion). + * + * @param string $assertionXpath Xpath Expression + * + * @return DOMNodeList The queried node + */ + protected function _queryAssertion($assertionXpath) + { + if ($this->encrypted) { + $xpath = new DOMXPath($this->decryptedDocument); + } else { + $xpath = new DOMXPath($this->document); + } + + $xpath->registerNamespace('samlp', OneLogin_Saml2_Constants::NS_SAMLP); + $xpath->registerNamespace('saml', OneLogin_Saml2_Constants::NS_SAML); + $xpath->registerNamespace('ds', OneLogin_Saml2_Constants::NS_DS); + $xpath->registerNamespace('xenc', OneLogin_Saml2_Constants::NS_XENC); + + $assertionNode = '/samlp:Response/saml:Assertion'; + $signatureQuery = $assertionNode . '/ds:Signature/ds:SignedInfo/ds:Reference'; + $assertionReferenceNode = $xpath->query($signatureQuery)->item(0); + if (!$assertionReferenceNode) { + // is the response signed as a whole? + $signatureQuery = '/samlp:Response/ds:Signature/ds:SignedInfo/ds:Reference'; + $responseReferenceNode = $xpath->query($signatureQuery)->item(0); + if ($responseReferenceNode) { + $uri = $responseReferenceNode->attributes->getNamedItem('URI')->nodeValue; + if (empty($uri)) { + $id = $responseReferenceNode->parentNode->parentNode->parentNode->attributes->getNamedItem('ID')->nodeValue; + } else { + $id = substr($responseReferenceNode->attributes->getNamedItem('URI')->nodeValue, 1); + } + $nameQuery = "/samlp:Response[@ID='$id']/saml:Assertion" . $assertionXpath; + } else { + $nameQuery = "/samlp:Response/saml:Assertion" . $assertionXpath; + } + } else { + $uri = $assertionReferenceNode->attributes->getNamedItem('URI')->nodeValue; + if (empty($uri)) { + $id = $assertionReferenceNode->parentNode->parentNode->parentNode->attributes->getNamedItem('ID')->nodeValue; + } else { + $id = substr($assertionReferenceNode->attributes->getNamedItem('URI')->nodeValue, 1); + } + $nameQuery = $assertionNode."[@ID='$id']" . $assertionXpath; + } + + return $xpath->query($nameQuery); + } + + /** + * Extracts nodes that match the query from the DOMDocument (Response Menssage) + * + * @param string $query Xpath Expresion + * + * @return DOMNodeList The queried nodes + */ + private function _query($query) + { + if ($this->encrypted) { + return OneLogin_Saml2_Utils::query($this->decryptedDocument, $query); + } else { + return OneLogin_Saml2_Utils::query($this->document, $query); + } + } + + /** + * Decrypts the Assertion (DOMDocument) + * + * @param DomNode $dom DomDocument + * + * @return DOMDocument Decrypted Assertion + * + * @throws OneLogin_Saml2_Error + * @throws OneLogin_Saml2_ValidationError + */ + protected function _decryptAssertion($dom) + { + $pem = $this->_settings->getSPkey(); + if (empty($pem)) { + throw new OneLogin_Saml2_Error( + "No private key available, check settings", + OneLogin_Saml2_Error::PRIVATE_KEY_NOT_FOUND + ); + } + $objenc = new XMLSecEnc(); + $encData = $objenc->locateEncryptedData($dom); + if (!$encData) { + throw new OneLogin_Saml2_ValidationError( + "Cannot locate encrypted assertion", + OneLogin_Saml2_ValidationError::MISSING_ENCRYPTED_ELEMENT + ); + } + $objenc->setNode($encData); + $objenc->type = $encData->getAttribute("Type"); + if (!$objKey = $objenc->locateKey()) { + throw new OneLogin_Saml2_ValidationError( + "Unknown algorithm", + OneLogin_Saml2_ValidationError::KEY_ALGORITHM_ERROR + ); + } + $key = null; + if ($objKeyInfo = $objenc->locateKeyInfo($objKey)) { + if ($objKeyInfo->isEncrypted) { + $objencKey = $objKeyInfo->encryptedCtx; + $objKeyInfo->loadKey($pem, false, false); + $key = $objencKey->decryptKey($objKeyInfo); + } else { + // symmetric encryption key support + $objKeyInfo->loadKey($pem, false, false); + } + } + + if (empty($objKey->key)) { + $objKey->loadKey($key); + } + $decryptedXML = $objenc->decryptNode($objKey, false); + $decrypted = new DOMDocument(); + $check = OneLogin_Saml2_Utils::loadXML($decrypted, $decryptedXML); + if ($check === false) { + throw new Exception('Error: string from decrypted assertion could not be loaded into a XML document'); + } + if ($encData->parentNode instanceof DOMDocument) { + return $decrypted; + } else { + $decrypted = $decrypted->documentElement; + $encryptedAssertion = $encData->parentNode; + $container = $encryptedAssertion->parentNode; + + // Fix possible issue with saml namespace + if (!$decrypted->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml') + && !$decrypted->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml2') + && !$decrypted->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns') + && !$container->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml') + && !$container->hasAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:saml2') + ) { + if (strpos($encryptedAssertion->tagName, 'saml2:') !== false) { + $ns = 'xmlns:saml2'; + } else if (strpos($encryptedAssertion->tagName, 'saml:') !== false) { + $ns = 'xmlns:saml'; + } else { + $ns = 'xmlns'; + } + $decrypted->setAttributeNS('http://www.w3.org/2000/xmlns/', $ns, OneLogin_Saml2_Constants::NS_SAML); + } + + OneLogin_Saml2_Utils::treeCopyReplace($encryptedAssertion, $decrypted); + + // Rebuild the DOM will fix issues with namespaces as well + $dom = new DOMDocument(); + return OneLogin_Saml2_Utils::loadXML($dom, $container->ownerDocument->saveXML()); + } + } + + /** + * After execute a validation process, if fails this method returns the cause + * + * @return string Cause + */ + public function getError() + { + return $this->_error; + } + + /** + * Returns the SAML Response document (If contains an encrypted assertion, decrypts it) + * + * @return DomDocument SAML Response + */ + public function getXMLDocument() + { + if ($this->encrypted) { + return $this->decryptedDocument; + } else { + return $this->document; + } + } +} + diff --git a/docs/Saml2/files/Settings.html b/docs/Saml2/files/Settings.html new file mode 100644 index 00000000..9d04cffd --- /dev/null +++ b/docs/Saml2/files/Settings.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

Settings.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_SettingsConfiguration of the PHP Toolkit
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/Settings.php.txt b/docs/Saml2/files/Settings.php.txt new file mode 100644 index 00000000..66e5e83b --- /dev/null +++ b/docs/Saml2/files/Settings.php.txt @@ -0,0 +1,1168 @@ +_spValidationOnly = $spValidationOnly; + $this->_loadPaths(); + + if (!isset($settings)) { + if (!$this->_loadSettingsFromFile()) { + throw new OneLogin_Saml2_Error( + 'Invalid file settings: %s', + OneLogin_Saml2_Error::SETTINGS_INVALID, + array(implode(', ', $this->_errors)) + ); + } + $this->_addDefaultValues(); + } else if (is_array($settings)) { + if (!$this->_loadSettingsFromArray($settings)) { + throw new OneLogin_Saml2_Error( + 'Invalid array settings: %s', + OneLogin_Saml2_Error::SETTINGS_INVALID, + array(implode(', ', $this->_errors)) + ); + } + } else if ($settings instanceof OneLogin_Saml2_Settings) { + throw new OneLogin_Saml2_Error( + 'Only instances of OneLogin_Saml_Settings are supported.', + OneLogin_Saml2_Error::UNSUPPORTED_SETTINGS_OBJECT, + array(implode(', ', $this->_errors)) + ); + } else { + if (!$this->_loadSettingsFromArray($settings->getValues())) { + throw new OneLogin_Saml2_Error( + 'Invalid array settings: %s', + OneLogin_Saml2_Error::SETTINGS_INVALID, + array(implode(', ', $this->_errors)) + ); + } + } + + $this->formatIdPCert(); + $this->formatSPCert(); + $this->formatSPKey(); + $this->formatSPCertNew(); + $this->formatIdPCertMulti(); + } + + /** + * Sets the paths of the different folders + * @suppress PhanUndeclaredConstant + */ + private function _loadPaths() + { + $basePath = dirname(dirname(__DIR__)).'/'; + $this->_paths = array ( + 'base' => $basePath, + 'config' => $basePath, + 'cert' => $basePath.'certs/', + 'lib' => __DIR__ . '/', + 'extlib' => $basePath.'extlib/' + ); + + if (defined('ONELOGIN_CUSTOMPATH')) { + $this->_paths['config'] = ONELOGIN_CUSTOMPATH; + $this->_paths['cert'] = ONELOGIN_CUSTOMPATH.'certs/'; + } + } + + /** + * Returns base path. + * + * @return string The base toolkit folder path + */ + public function getBasePath() + { + return $this->_paths['base']; + } + + /** + * Returns cert path. + * + * @return string The cert folder path + */ + public function getCertPath() + { + return $this->_paths['cert']; + } + + /** + * Returns config path. + * + * @return string The config folder path + */ + public function getConfigPath() + { + return $this->_paths['config']; + } + + /** + * Returns lib path. + * + * @return string The library folder path + */ + public function getLibPath() + { + return $this->_paths['lib']; + } + + /** + * Returns external lib path. + * + * @return string The external library folder path + */ + public function getExtLibPath() + { + return $this->_paths['extlib']; + } + + /** + * Returns schema path. + * + * @return string The external library folder path + */ + public function getSchemasPath() + { + if (isset($this->_paths['schemas'])) { + return $this->_paths['schemas']; + } + return __DIR__ . '/schemas/'; + } + + /** + * Set schemas path + * + * @param string $path + * @return $this + */ + public function setSchemasPath($path) + { + $this->_paths['schemas'] = $path; + } + + /** + * Loads settings info from a settings Array + * + * @param array $settings SAML Toolkit Settings + * + * @return bool True if the settings info is valid + */ + private function _loadSettingsFromArray($settings) + { + if (isset($settings['sp'])) { + $this->_sp = $settings['sp']; + } + if (isset($settings['idp'])) { + $this->_idp = $settings['idp']; + } + + $errors = $this->checkSettings($settings); + if (empty($errors)) { + $this->_errors = array(); + + if (isset($settings['strict'])) { + $this->_strict = $settings['strict']; + } + if (isset($settings['debug'])) { + $this->_debug = $settings['debug']; + } + + if (isset($settings['baseurl'])) { + $this->_baseurl = $settings['baseurl']; + } + + if (isset($settings['compress'])) { + $this->_compress = $settings['compress']; + } + + if (isset($settings['security'])) { + $this->_security = $settings['security']; + } + + if (isset($settings['contactPerson'])) { + $this->_contacts = $settings['contactPerson']; + } + + if (isset($settings['organization'])) { + $this->_organization = $settings['organization']; + } + + $this->_addDefaultValues(); + return true; + } else { + $this->_errors = $errors; + return false; + } + } + + /** + * Loads settings info from the settings file + * + * @return bool True if the settings info is valid + * + * @throws OneLogin_Saml2_Error + * + * @suppress PhanUndeclaredVariable + */ + private function _loadSettingsFromFile() + { + $filename = $this->getConfigPath().'settings.php'; + + if (!file_exists($filename)) { + throw new OneLogin_Saml2_Error( + 'Settings file not found: %s', + OneLogin_Saml2_Error::SETTINGS_FILE_NOT_FOUND, + array($filename) + ); + } + + /** @var array $settings */ + include $filename; + + // Add advance_settings if exists + + $advancedFilename = $this->getConfigPath().'advanced_settings.php'; + + if (file_exists($advancedFilename)) { + /** @var array $advancedSettings */ + include $advancedFilename; + $settings = array_merge($settings, $advancedSettings); + } + + + return $this->_loadSettingsFromArray($settings); + } + + /** + * Add default values if the settings info is not complete + */ + private function _addDefaultValues() + { + if (!isset($this->_sp['assertionConsumerService']['binding'])) { + $this->_sp['assertionConsumerService']['binding'] = OneLogin_Saml2_Constants::BINDING_HTTP_POST; + } + if (isset($this->_sp['singleLogoutService']) && !isset($this->_sp['singleLogoutService']['binding'])) { + $this->_sp['singleLogoutService']['binding'] = OneLogin_Saml2_Constants::BINDING_HTTP_REDIRECT; + } + + if (!isset($this->_compress['requests'])) { + $this->_compress['requests'] = true; + } + + if (!isset($this->_compress['responses'])) { + $this->_compress['responses'] = true; + } + + // Related to nameID + if (!isset($this->_sp['NameIDFormat'])) { + $this->_sp['NameIDFormat'] = OneLogin_Saml2_Constants::NAMEID_UNSPECIFIED; + } + if (!isset($this->_security['nameIdEncrypted'])) { + $this->_security['nameIdEncrypted'] = false; + } + if (!isset($this->_security['requestedAuthnContext'])) { + $this->_security['requestedAuthnContext'] = true; + } + + // sign provided + if (!isset($this->_security['authnRequestsSigned'])) { + $this->_security['authnRequestsSigned'] = false; + } + if (!isset($this->_security['logoutRequestSigned'])) { + $this->_security['logoutRequestSigned'] = false; + } + if (!isset($this->_security['logoutResponseSigned'])) { + $this->_security['logoutResponseSigned'] = false; + } + if (!isset($this->_security['signMetadata'])) { + $this->_security['signMetadata'] = false; + } + + // sign expected + if (!isset($this->_security['wantMessagesSigned'])) { + $this->_security['wantMessagesSigned'] = false; + } + if (!isset($this->_security['wantAssertionsSigned'])) { + $this->_security['wantAssertionsSigned'] = false; + } + + // NameID element expected + if (!isset($this->_security['wantNameId'])) { + $this->_security['wantNameId'] = true; + } + + // Relax Destination validation + if (!isset($this->_security['relaxDestinationValidation'])) { + $this->_security['relaxDestinationValidation'] = false; + } + + // Allow duplicated Attribute Names + if (!isset($this->_security['allowRepeatAttributeName'])) { + $this->_security['allowRepeatAttributeName'] = false; + } + + // Strict Destination match validation + if (!isset($this->_security['destinationStrictlyMatches'])) { + $this->_security['destinationStrictlyMatches'] = false; + } + + // InResponseTo + if (!isset($this->_security['rejectUnsolicitedResponsesWithInResponseTo'])) { + $this->_security['rejectUnsolicitedResponsesWithInResponseTo'] = false; + } + + // encrypt expected + if (!isset($this->_security['wantAssertionsEncrypted'])) { + $this->_security['wantAssertionsEncrypted'] = false; + } + if (!isset($this->_security['wantNameIdEncrypted'])) { + $this->_security['wantNameIdEncrypted'] = false; + } + + // XML validation + if (!isset($this->_security['wantXMLValidation'])) { + $this->_security['wantXMLValidation'] = true; + } + + // SignatureAlgorithm + if (!isset($this->_security['signatureAlgorithm'])) { + $this->_security['signatureAlgorithm'] = XMLSecurityKey::RSA_SHA1; + } + + // DigestAlgorithm + if (!isset($this->_security['digestAlgorithm'])) { + $this->_security['digestAlgorithm'] = XMLSecurityDSig::SHA1; + } + + if (!isset($this->_security['lowercaseUrlencoding'])) { + $this->_security['lowercaseUrlencoding'] = false; + } + + // Certificates / Private key /Fingerprint + if (!isset($this->_idp['x509cert'])) { + $this->_idp['x509cert'] = ''; + } + if (!isset($this->_idp['certFingerprint'])) { + $this->_idp['certFingerprint'] = ''; + } + if (!isset($this->_idp['certFingerprintAlgorithm'])) { + $this->_idp['certFingerprintAlgorithm'] = 'sha1'; + } + + if (!isset($this->_sp['x509cert'])) { + $this->_sp['x509cert'] = ''; + } + if (!isset($this->_sp['privateKey'])) { + $this->_sp['privateKey'] = ''; + } + } + + /** + * Checks the settings info. + * + * @param array $settings Array with settings data + * + * @return array $errors Errors found on the settings data + */ + public function checkSettings($settings) + { + assert('is_array($settings)'); + + if (!is_array($settings) || empty($settings)) { + $errors = array('invalid_syntax'); + } else { + $errors = array(); + if (!$this->_spValidationOnly) { + $idpErrors = $this->checkIdPSettings($settings); + $errors = array_merge($idpErrors, $errors); + } + $spErrors = $this->checkSPSettings($settings); + $errors = array_merge($spErrors, $errors); + + $compressErrors = $this->checkCompressionSettings($settings); + $errors = array_merge($compressErrors, $errors); + } + + return $errors; + } + + /** + * Checks the compression settings info. + * + * @param array $settings Array with settings data + * + * @return array $errors Errors found on the settings data + */ + public function checkCompressionSettings($settings) + { + $errors = array(); + + if (isset($settings['compress'])) { + if (!is_array($settings['compress'])) { + $errors[] = "invalid_syntax"; + } else if (isset($settings['compress']['requests']) + && $settings['compress']['requests'] !== true + && $settings['compress']['requests'] !== false + ) { + $errors[] = "'compress'=>'requests' values must be true or false."; + } else if (isset($settings['compress']['responses']) + && $settings['compress']['responses'] !== true + && $settings['compress']['responses'] !== false + ) { + $errors[] = "'compress'=>'responses' values must be true or false."; + } + } + return $errors; + } + + /** + * Checks the IdP settings info. + * + * @param array $settings Array with settings data + * + * @return array $errors Errors found on the IdP settings data + */ + public function checkIdPSettings($settings) + { + assert('is_array($settings)'); + + if (!is_array($settings) || empty($settings)) { + return array('invalid_syntax'); + } + + $errors = array(); + + if (!isset($settings['idp']) || empty($settings['idp'])) { + $errors[] = 'idp_not_found'; + } else { + $idp = $settings['idp']; + if (!isset($idp['entityId']) || empty($idp['entityId'])) { + $errors[] = 'idp_entityId_not_found'; + } + + if (!isset($idp['singleSignOnService']) + || !isset($idp['singleSignOnService']['url']) + || empty($idp['singleSignOnService']['url']) + ) { + $errors[] = 'idp_sso_not_found'; + } else if (!filter_var($idp['singleSignOnService']['url'], FILTER_VALIDATE_URL)) { + $errors[] = 'idp_sso_url_invalid'; + } + + if (isset($idp['singleLogoutService']) + && isset($idp['singleLogoutService']['url']) + && !empty($idp['singleLogoutService']['url']) + && !filter_var($idp['singleLogoutService']['url'], FILTER_VALIDATE_URL) + ) { + $errors[] = 'idp_slo_url_invalid'; + } + + if (isset($idp['singleLogoutService']) + && isset($idp['singleLogoutService']['responseUrl']) + && !empty($idp['singleLogoutService']['responseUrl']) + && !filter_var($idp['singleLogoutService']['responseUrl'], FILTER_VALIDATE_URL) + ) { + $errors[] = 'idp_slo_response_url_invalid'; + } + + $existsX509 = isset($idp['x509cert']) && !empty($idp['x509cert']); + $existsMultiX509Sign = isset($idp['x509certMulti']) && isset($idp['x509certMulti']['signing']) && !empty($idp['x509certMulti']['signing']); + $existsFingerprint = isset($idp['certFingerprint']) && !empty($idp['certFingerprint']); + + if (!($existsX509 || $existsFingerprint || $existsMultiX509Sign) + ) { + $errors[] = 'idp_cert_or_fingerprint_not_found_and_required'; + } + + if (isset($settings['security'])) { + $existsMultiX509Enc = isset($idp['x509certMulti']) && isset($idp['x509certMulti']['encryption']) && !empty($idp['x509certMulti']['encryption']); + + if ((isset($settings['security']['nameIdEncrypted']) && $settings['security']['nameIdEncrypted'] == true) + && !($existsX509 || $existsMultiX509Enc) + ) { + $errors[] = 'idp_cert_not_found_and_required'; + } + } + } + + return $errors; + } + + /** + * Checks the SP settings info. + * + * @param array $settings Array with settings data + * + * @return array $errors Errors found on the SP settings data + */ + public function checkSPSettings($settings) + { + assert('is_array($settings)'); + + if (!is_array($settings) || empty($settings)) { + return array('invalid_syntax'); + } + + $errors = array(); + + if (!isset($settings['sp']) || empty($settings['sp'])) { + $errors[] = 'sp_not_found'; + } else { + $sp = $settings['sp']; + $security = array(); + if (isset($settings['security'])) { + $security = $settings['security']; + } + + if (!isset($sp['entityId']) || empty($sp['entityId'])) { + $errors[] = 'sp_entityId_not_found'; + } + + if (!isset($sp['assertionConsumerService']) + || !isset($sp['assertionConsumerService']['url']) + || empty($sp['assertionConsumerService']['url']) + ) { + $errors[] = 'sp_acs_not_found'; + } else if (!filter_var($sp['assertionConsumerService']['url'], FILTER_VALIDATE_URL)) { + $errors[] = 'sp_acs_url_invalid'; + } + + if (isset($sp['singleLogoutService']) + && isset($sp['singleLogoutService']['url']) + && !filter_var($sp['singleLogoutService']['url'], FILTER_VALIDATE_URL) + ) { + $errors[] = 'sp_sls_url_invalid'; + } + + if (isset($security['signMetadata']) && is_array($security['signMetadata'])) { + if ((!isset($security['signMetadata']['keyFileName']) + || !isset($security['signMetadata']['certFileName'])) && + (!isset($security['signMetadata']['privateKey']) + || !isset($security['signMetadata']['x509cert'])) + ) { + $errors[] = 'sp_signMetadata_invalid'; + } + } + + if (((isset($security['authnRequestsSigned']) && $security['authnRequestsSigned'] == true) + || (isset($security['logoutRequestSigned']) && $security['logoutRequestSigned'] == true) + || (isset($security['logoutResponseSigned']) && $security['logoutResponseSigned'] == true) + || (isset($security['wantAssertionsEncrypted']) && $security['wantAssertionsEncrypted'] == true) + || (isset($security['wantNameIdEncrypted']) && $security['wantNameIdEncrypted'] == true)) + && !$this->checkSPCerts() + ) { + $errors[] = 'sp_certs_not_found_and_required'; + } + } + + if (isset($settings['contactPerson'])) { + $types = array_keys($settings['contactPerson']); + $validTypes = array('technical', 'support', 'administrative', 'billing', 'other'); + foreach ($types as $type) { + if (!in_array($type, $validTypes)) { + $errors[] = 'contact_type_invalid'; + break; + } + } + + foreach ($settings['contactPerson'] as $type => $contact) { + if (!isset($contact['givenName']) || empty($contact['givenName']) + || !isset($contact['emailAddress']) || empty($contact['emailAddress']) + ) { + $errors[] = 'contact_not_enought_data'; + break; + } + } + } + + if (isset($settings['organization'])) { + foreach ($settings['organization'] as $organization) { + if (!isset($organization['name']) || empty($organization['name']) + || !isset($organization['displayname']) || empty($organization['displayname']) + || !isset($organization['url']) || empty($organization['url']) + ) { + $errors[] = 'organization_not_enough_data'; + break; + } + } + } + + return $errors; + } + + /** + * Checks if the x509 certs of the SP exists and are valid. + * + * @return bool + */ + public function checkSPCerts() + { + $key = $this->getSPkey(); + $cert = $this->getSPcert(); + return (!empty($key) && !empty($cert)); + } + + /** + * Returns the x509 private key of the SP. + * + * @return string SP private key + */ + public function getSPkey() + { + $key = null; + if (isset($this->_sp['privateKey']) && !empty($this->_sp['privateKey'])) { + $key = $this->_sp['privateKey']; + } else { + $keyFile = $this->_paths['cert'].'sp.key'; + + if (file_exists($keyFile)) { + $key = file_get_contents($keyFile); + } + } + return $key; + } + + /** + * Returns the x509 public cert of the SP. + * + * @return string SP public cert + */ + public function getSPcert() + { + $cert = null; + + if (isset($this->_sp['x509cert']) && !empty($this->_sp['x509cert'])) { + $cert = $this->_sp['x509cert']; + } else { + $certFile = $this->_paths['cert'].'sp.crt'; + + if (file_exists($certFile)) { + $cert = file_get_contents($certFile); + } + } + return $cert; + } + + /** + * Returns the x509 public of the SP that is + * planed to be used soon instead the other + * public cert + * @return string SP public cert New + */ + public function getSPcertNew() + { + $cert = null; + + if (isset($this->_sp['x509certNew']) && !empty($this->_sp['x509certNew'])) { + $cert = $this->_sp['x509certNew']; + } else { + $certFile = $this->_paths['cert'].'sp_new.crt'; + + if (file_exists($certFile)) { + $cert = file_get_contents($certFile); + } + } + return $cert; + } + + /** + * Gets the IdP data. + * + * @return array IdP info + */ + public function getIdPData() + { + return $this->_idp; + } + + /** + * Gets the SP data. + * + * @return array SP info + */ + public function getSPData() + { + return $this->_sp; + } + + /** + * Gets security data. + * + * @return array SP info + */ + public function getSecurityData() + { + return $this->_security; + } + + /** + * Gets contact data. + * + * @return array SP info + */ + public function getContacts() + { + return $this->_contacts; + } + + /** + * Gets organization data. + * + * @return array SP info + */ + public function getOrganization() + { + return $this->_organization; + } + + /** + * Should SAML requests be compressed? + * + * @return bool Yes/No as True/False + */ + public function shouldCompressRequests() + { + return $this->_compress['requests']; + } + + /** + * Should SAML responses be compressed? + * + * @return bool Yes/No as True/False + */ + public function shouldCompressResponses() + { + return $this->_compress['responses']; + } + + /** + * Gets the IdP SSO url. + * + * @return string|null The url of the IdP Single Sign On Service + */ + public function getIdPSSOUrl() + { + $ssoUrl = null; + if (isset($this->_idp['singleSignOnService']) && isset($this->_idp['singleSignOnService']['url'])) { + $ssoUrl = $this->_idp['singleSignOnService']['url']; + } + return $ssoUrl; + } + + /** + * Gets the IdP SLO url. + * + * @return string|null The request url of the IdP Single Logout Service + */ + public function getIdPSLOUrl() + { + $sloUrl = null; + if (isset($this->_idp['singleLogoutService']) && isset($this->_idp['singleLogoutService']['url'])) { + $sloUrl = $this->_idp['singleLogoutService']['url']; + } + return $sloUrl; + } + + /** + * Gets the IdP SLO response url. + * + * @return string|null The response url of the IdP Single Logout Service + */ + public function getIdPSLOResponseUrl() + { + if (isset($this->_idp['singleLogoutService']) && isset($this->_idp['singleLogoutService']['responseUrl'])) { + return $this->_idp['singleLogoutService']['responseUrl']; + } + return $this->getIdPSLOUrl(); + } + + /** + * Gets the SP metadata. The XML representation. + * + * @param bool $alwaysPublishEncryptionCert When 'true', the returned metadata + * will always include an 'encryption' KeyDescriptor. Otherwise, the 'encryption' + * KeyDescriptor will only be included if $advancedSettings['security']['wantNameIdEncrypted'] + * or $advancedSettings['security']['wantAssertionsEncrypted'] are enabled. + * @param DateTime|null $validUntil Metadata's valid time + * @param int|null $cacheDuration Duration of the cache in seconds + * + * @return string SP metadata (xml) + * + * @throws Exception + * @throws OneLogin_Saml2_Error + */ + public function getSPMetadata($alwaysPublishEncryptionCert = false, $validUntil = null, $cacheDuration = null) + { + $metadata = OneLogin_Saml2_Metadata::builder($this->_sp, $this->_security['authnRequestsSigned'], $this->_security['wantAssertionsSigned'], $validUntil, $cacheDuration, $this->getContacts(), $this->getOrganization()); + + $certNew = $this->getSPcertNew(); + if (!empty($certNew)) { + $metadata = OneLogin_Saml2_Metadata::addX509KeyDescriptors( + $metadata, + $certNew, + $alwaysPublishEncryptionCert || $this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted'] + ); + } + + $cert = $this->getSPcert(); + if (!empty($cert)) { + $metadata = OneLogin_Saml2_Metadata::addX509KeyDescriptors( + $metadata, + $cert, + $alwaysPublishEncryptionCert || $this->_security['wantNameIdEncrypted'] || $this->_security['wantAssertionsEncrypted'] + ); + } + + //Sign Metadata + if (isset($this->_security['signMetadata']) && $this->_security['signMetadata'] !== false) { + if ($this->_security['signMetadata'] === true) { + $keyMetadata = $this->getSPkey(); + $certMetadata = $cert; + if (!$keyMetadata) { + throw new OneLogin_Saml2_Error( + 'SP Private key not found.', + OneLogin_Saml2_Error::PRIVATE_KEY_FILE_NOT_FOUND + ); + } + if (!$certMetadata) { + throw new OneLogin_Saml2_Error( + 'SP Public cert not found.', + OneLogin_Saml2_Error::PUBLIC_CERT_FILE_NOT_FOUND + ); + } + } else if (isset($this->_security['signMetadata']['keyFileName']) && + isset($this->_security['signMetadata']['certFileName'])) { + $keyFileName = $this->_security['signMetadata']['keyFileName']; + $certFileName = $this->_security['signMetadata']['certFileName']; + $keyMetadataFile = $this->_paths['cert'].$keyFileName; + $certMetadataFile = $this->_paths['cert'].$certFileName; + if (!file_exists($keyMetadataFile)) { + throw new OneLogin_Saml2_Error( + 'SP Private key file not found: %s', + OneLogin_Saml2_Error::PRIVATE_KEY_FILE_NOT_FOUND, + array($keyMetadataFile) + ); + } + if (!file_exists($certMetadataFile)) { + throw new OneLogin_Saml2_Error( + 'SP Public cert file not found: %s', + OneLogin_Saml2_Error::PUBLIC_CERT_FILE_NOT_FOUND, + array($certMetadataFile) + ); + } + $keyMetadata = file_get_contents($keyMetadataFile); + $certMetadata = file_get_contents($certMetadataFile); + } else if (isset($this->_security['signMetadata']['privateKey']) && + isset($this->_security['signMetadata']['x509cert'])) { + $keyMetadata = OneLogin_Saml2_Utils::formatPrivateKey($this->_security['signMetadata']['privateKey']); + $certMetadata = OneLogin_Saml2_Utils::formatCert($this->_security['signMetadata']['x509cert']); + if (!$keyMetadata) { + throw new OneLogin_Saml2_Error( + 'Private key not found.', + OneLogin_Saml2_Error::PRIVATE_KEY_FILE_NOT_FOUND + ); + } + if (!$certMetadata) { + throw new OneLogin_Saml2_Error( + 'Public cert not found.', + OneLogin_Saml2_Error::PUBLIC_CERT_FILE_NOT_FOUND + ); + } + } else { + throw new OneLogin_Saml2_Error( + 'Invalid Setting: signMetadata value of the sp is not valid', + OneLogin_Saml2_Error::SETTINGS_INVALID_SYNTAX + ); + } + + $signatureAlgorithm = $this->_security['signatureAlgorithm']; + $digestAlgorithm = $this->_security['digestAlgorithm']; + $metadata = OneLogin_Saml2_Metadata::signMetadata($metadata, $keyMetadata, $certMetadata, $signatureAlgorithm, $digestAlgorithm); + } + return $metadata; + } + + /** + * Validates an XML SP Metadata. + * + * @param string $xml Metadata's XML that will be validate + * + * @return Array The list of found errors + * + * @throws Exception + */ + public function validateMetadata($xml) + { + assert('is_string($xml)'); + + $errors = array(); + $res = OneLogin_Saml2_Utils::validateXML($xml, 'saml-schema-metadata-2.0.xsd', $this->_debug, $this->getSchemasPath()); + if (!$res instanceof DOMDocument) { + $errors[] = $res; + } else { + $dom = $res; + $element = $dom->documentElement; + if ($element->tagName !== 'md:EntityDescriptor') { + $errors[] = 'noEntityDescriptor_xml'; + } else { + $validUntil = $cacheDuration = $expireTime = null; + + if ($element->hasAttribute('validUntil')) { + $validUntil = OneLogin_Saml2_Utils::parseSAML2Time($element->getAttribute('validUntil')); + } + if ($element->hasAttribute('cacheDuration')) { + $cacheDuration = $element->getAttribute('cacheDuration'); + } + + $expireTime = OneLogin_Saml2_Utils::getExpireTime($cacheDuration, $validUntil); + if (isset($expireTime) && time() > $expireTime) { + $errors[] = 'expired_xml'; + } + } + } + + // TODO: Support Metadata Sign Validation + + return $errors; + } + + /** + * Formats the IdP cert. + */ + public function formatIdPCert() + { + if (isset($this->_idp['x509cert'])) { + $this->_idp['x509cert'] = OneLogin_Saml2_Utils::formatCert($this->_idp['x509cert']); + } + } + + /** + * Formats the Multple IdP certs. + */ + public function formatIdPCertMulti() + { + if (isset($this->_idp['x509certMulti'])) { + if (isset($this->_idp['x509certMulti']['signing'])) { + foreach ($this->_idp['x509certMulti']['signing'] as $i => $cert) { + $this->_idp['x509certMulti']['signing'][$i] = OneLogin_Saml2_Utils::formatCert($cert); + } + } + if (isset($this->_idp['x509certMulti']['encryption'])) { + foreach ($this->_idp['x509certMulti']['encryption'] as $i => $cert) { + $this->_idp['x509certMulti']['encryption'][$i] = OneLogin_Saml2_Utils::formatCert($cert); + } + } + } + } + + /** + * Formats the SP cert. + */ + public function formatSPCert() + { + if (isset($this->_sp['x509cert'])) { + $this->_sp['x509cert'] = OneLogin_Saml2_Utils::formatCert($this->_sp['x509cert']); + } + } + + /** + * Formats the SP cert. + */ + public function formatSPCertNew() + { + if (isset($this->_sp['x509certNew'])) { + $this->_sp['x509certNew'] = OneLogin_Saml2_Utils::formatCert($this->_sp['x509certNew']); + } + } + + /** + * Formats the SP private key. + */ + public function formatSPKey() + { + if (isset($this->_sp['privateKey'])) { + $this->_sp['privateKey'] = OneLogin_Saml2_Utils::formatPrivateKey($this->_sp['privateKey']); + } + } + + /** + * Returns an array with the errors, the array is empty when the settings is ok. + * + * @return array Errors + */ + public function getErrors() + { + return $this->_errors; + } + + /** + * Activates or deactivates the strict mode. + * + * @param bool $value Strict parameter + * + * @throws Exception + */ + public function setStrict($value) + { + if (!is_bool($value)) { + throw new Exception('Invalid value passed to setStrict()'); + } + + $this->_strict = $value; + } + + /** + * Returns if the 'strict' mode is active. + * + * @return bool Strict parameter + */ + public function isStrict() + { + return $this->_strict; + } + + /** + * Returns if the debug is active. + * + * @return bool Debug parameter + */ + public function isDebugActive() + { + return $this->_debug; + } + + /** + * Set a baseurl value. + * + * @param $baseurl + */ + public function setBaseURL($baseurl) + { + $this->_baseurl = $baseurl; + } + + /** + * Returns the baseurl set on the settings if any. + * + * @return null|string The baseurl + */ + public function getBaseURL() + { + return $this->_baseurl; + } + + /** + * Sets the IdP certificate. + * + * @param string $cert IdP certificate + */ + public function setIdPCert($cert) + { + $this->_idp['x509cert'] = $cert; + $this->formatIdPCert(); + } +} + diff --git a/docs/Saml2/files/Utils.html b/docs/Saml2/files/Utils.html new file mode 100644 index 00000000..6e9a4328 --- /dev/null +++ b/docs/Saml2/files/Utils.html @@ -0,0 +1,264 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ + + +

Utils.php

+

+ + + + +

Classes

+ + + + + +
OneLogin_Saml2_UtilsUtils of PHP Toolkit
+
+ + +
+ + + +
+
+ + + + +
+ + + diff --git a/docs/Saml2/files/Utils.php.txt b/docs/Saml2/files/Utils.php.txt new file mode 100644 index 00000000..35d635fb --- /dev/null +++ b/docs/Saml2/files/Utils.php.txt @@ -0,0 +1,1568 @@ +loadXML($xml); + + libxml_disable_entity_loader($oldEntityLoader); + + foreach ($dom->childNodes as $child) { + if ($child->nodeType === XML_DOCUMENT_TYPE_NODE) { + throw new Exception( + 'Detected use of DOCTYPE/ENTITY in XML, disabled to prevent XXE/XEE attacks' + ); + } + } + + if (!$res) { + return false; + } else { + return $dom; + } + } + + /** + * This function attempts to validate an XML string against the specified schema. + * + * It will parse the string into a DOM document and validate this document against the schema. + * + * @param string|DOMDocument $xml The XML string or document which should be validated. + * @param string $schema The schema filename which should be used. + * @param bool $debug To disable/enable the debug mode + * @param string $schemaPath Change schema path + * + * @return string|DOMDocument $dom string that explains the problem or the DOMDocument + * + * @throws Exception + */ + public static function validateXML($xml, $schema, $debug = false, $schemaPath = null) + { + assert('is_string($xml) || $xml instanceof DOMDocument'); + assert('is_string($schema)'); + + libxml_clear_errors(); + libxml_use_internal_errors(true); + + if ($xml instanceof DOMDocument) { + $dom = $xml; + } else { + $dom = new DOMDocument; + $dom = self::loadXML($dom, $xml); + if (!$dom) { + return 'unloaded_xml'; + } + } + + if (isset($schemaPath)) { + $schemaFile = $schemaPath . $schema; + } else { + $schemaFile = __DIR__ . '/schemas/' . $schema; + } + + $oldEntityLoader = libxml_disable_entity_loader(false); + $res = $dom->schemaValidate($schemaFile); + libxml_disable_entity_loader($oldEntityLoader); + if (!$res) { + $xmlErrors = libxml_get_errors(); + syslog(LOG_INFO, 'Error validating the metadata: '.var_export($xmlErrors, true)); + + if ($debug) { + foreach ($xmlErrors as $error) { + echo htmlentities($error->message."\n"); + } + } + + return 'invalid_xml'; + } + + + return $dom; + } + + /** + * Import a node tree into a target document + * Copy it before a reference node as a sibling + * and at the end of the copy remove + * the reference node in the target document + * As it were 'replacing' it + * Leaving nested default namespaces alone + * (Standard importNode with deep copy + * mangles nested default namespaces) + * + * The reference node must not be a DomDocument + * It CAN be the top element of a document + * Returns the copied node in the target document + * + * @param DomNode $targetNode + * @param DomNode $sourceNode + * @param bool $recurse + * @return DOMNode + * @throws Exception + */ + public static function treeCopyReplace(DomNode $targetNode, DomNode $sourceNode, $recurse = false) + { + if ($targetNode->parentNode === null) { + throw new Exception('Illegal argument targetNode. It has no parentNode.'); + } + $clonedNode = $targetNode->ownerDocument->importNode($sourceNode, false); + if ($recurse) { + $resultNode = $targetNode->appendChild($clonedNode); + } else { + $resultNode = $targetNode->parentNode->insertBefore($clonedNode, $targetNode); + } + if ($sourceNode->childNodes !== null) { + foreach ($sourceNode->childNodes as $child) { + self::treeCopyReplace($resultNode, $child, true); + } + } + if (!$recurse) { + $targetNode->parentNode->removeChild($targetNode); + } + return $resultNode; + } + + /** + * Returns a x509 cert (adding header & footer if required). + * + * @param string $cert A x509 unformated cert + * @param bool $heads True if we want to include head and footer + * + * @return string $x509 Formatted cert + */ + + public static function formatCert($cert, $heads = true) + { + $x509cert = str_replace(array("\x0D", "\r", "\n"), "", $cert); + if (!empty($x509cert)) { + $x509cert = str_replace('-----BEGIN CERTIFICATE-----', "", $x509cert); + $x509cert = str_replace('-----END CERTIFICATE-----', "", $x509cert); + $x509cert = str_replace(' ', '', $x509cert); + + if ($heads) { + $x509cert = "-----BEGIN CERTIFICATE-----\n".chunk_split($x509cert, 64, "\n")."-----END CERTIFICATE-----\n"; + } + + } + return $x509cert; + } + + /** + * Returns a private key (adding header & footer if required). + * + * @param string $key A private key + * @param bool $heads True if we want to include head and footer + * + * @return string $rsaKey Formatted private key + */ + + public static function formatPrivateKey($key, $heads = true) + { + $key = str_replace(array("\x0D", "\r", "\n"), "", $key); + if (!empty($key)) { + if (strpos($key, '-----BEGIN PRIVATE KEY-----') !== false) { + $key = OneLogin_Saml2_Utils::getStringBetween($key, '-----BEGIN PRIVATE KEY-----', '-----END PRIVATE KEY-----'); + $key = str_replace(' ', '', $key); + + if ($heads) { + $key = "-----BEGIN PRIVATE KEY-----\n".chunk_split($key, 64, "\n")."-----END PRIVATE KEY-----\n"; + } + } else if (strpos($key, '-----BEGIN RSA PRIVATE KEY-----') !== false) { + $key = OneLogin_Saml2_Utils::getStringBetween($key, '-----BEGIN RSA PRIVATE KEY-----', '-----END RSA PRIVATE KEY-----'); + $key = str_replace(' ', '', $key); + + if ($heads) { + $key = "-----BEGIN RSA PRIVATE KEY-----\n".chunk_split($key, 64, "\n")."-----END RSA PRIVATE KEY-----\n"; + } + } else { + $key = str_replace(' ', '', $key); + + if ($heads) { + $key = "-----BEGIN RSA PRIVATE KEY-----\n".chunk_split($key, 64, "\n")."-----END RSA PRIVATE KEY-----\n"; + } + } + } + return $key; + } + + /** + * Extracts a substring between 2 marks + * + * @param string $str The target string + * @param string $start The initial mark + * @param string $end The end mark + * + * @return string A substring or an empty string if is not able to find the marks + * or if there is no string between the marks + */ + public static function getStringBetween($str, $start, $end) + { + $str = ' ' . $str; + $ini = strpos($str, $start); + + if ($ini == 0) { + return ''; + } + + $ini += strlen($start); + $len = strpos($str, $end, $ini) - $ini; + return substr($str, $ini, $len); + } + + /** + * Executes a redirection to the provided url (or return the target url). + * + * @param string $url The target url + * @param array $parameters Extra parameters to be passed as part of the url + * @param bool $stay True if we want to stay (returns the url string) False to redirect + * + * @return string|null $url + * + * @throws OneLogin_Saml2_Error + */ + public static function redirect($url, $parameters = array(), $stay = false) + { + assert('is_string($url)'); + assert('is_array($parameters)'); + + if (substr($url, 0, 1) === '/') { + $url = self::getSelfURLhost() . $url; + } + + /** + * Verify that the URL matches the regex for the protocol. + * By default this will check for http and https + */ + $wrongProtocol = !preg_match(self::$_protocolRegex, $url); + $url = filter_var($url, FILTER_VALIDATE_URL); + if ($wrongProtocol || empty($url)) { + throw new OneLogin_Saml2_Error( + 'Redirect to invalid URL: ' . $url, + OneLogin_Saml2_Error::REDIRECT_INVALID_URL + ); + } + + /* Add encoded parameters */ + if (strpos($url, '?') === false) { + $paramPrefix = '?'; + } else { + $paramPrefix = '&'; + } + + foreach ($parameters as $name => $value) { + if ($value === null) { + $param = urlencode($name); + } else if (is_array($value)) { + $param = ""; + foreach ($value as $val) { + $param .= urlencode($name) . "[]=" . urlencode($val). '&'; + } + if (!empty($param)) { + $param = substr($param, 0, -1); + } + } else { + $param = urlencode($name) . '=' . urlencode($value); + } + + if (!empty($param)) { + $url .= $paramPrefix . $param; + $paramPrefix = '&'; + } + } + + if ($stay) { + return $url; + } + + header('Pragma: no-cache'); + header('Cache-Control: no-cache, must-revalidate'); + header('Location: ' . $url); + exit(); + } + + /** + * @var $protocolRegex string + */ + public static function setProtocolRegex($protocolRegex) + { + if (!empty($protocolRegex)) { + self::$_protocolRegex = $protocolRegex; + } + } + + /** + * @param $baseurl string The base url to be used when constructing URLs + */ + public static function setBaseURL($baseurl) + { + if (!empty($baseurl)) { + $baseurlpath = '/'; + if (preg_match('#^https?://([^/]*)/?(.*)#i', $baseurl, $matches)) { + if (strpos($baseurl, 'https://') === false) { + self::setSelfProtocol('http'); + $port = '80'; + } else { + self::setSelfProtocol('https'); + $port = '443'; + } + + $currentHost = $matches[1]; + if (false !== strpos($currentHost, ':')) { + list($currentHost, $possiblePort) = explode(':', $matches[1], 2); + if (is_numeric($possiblePort)) { + $port = $possiblePort; + } + } + + if (isset($matches[2]) && !empty($matches[2])) { + $baseurlpath = $matches[2]; + } + + self::setSelfHost($currentHost); + self::setSelfPort($port); + self::setBaseURLPath($baseurlpath); + } + } else { + self::$_host = null; + self::$_protocol = null; + self::$_port = null; + self::$_baseurlpath = null; + } + } + + /** + * @param $proxyVars bool Whether to use `X-Forwarded-*` headers to determine port/domain/protocol + */ + public static function setProxyVars($proxyVars) + { + self::$_proxyVars = (bool)$proxyVars; + } + + /** + * return bool + */ + public static function getProxyVars() + { + return self::$_proxyVars; + } + + /** + * Returns the protocol + the current host + the port (if different than + * common ports). + * + * @return string $url + */ + public static function getSelfURLhost() + { + $currenthost = self::getSelfHost(); + + $port = ''; + + if (self::isHTTPS()) { + $protocol = 'https'; + } else { + $protocol = 'http'; + } + + $portnumber = self::getSelfPort(); + + if (isset($portnumber) && ($portnumber != '80') && ($portnumber != '443')) { + $port = ':' . $portnumber; + } + + return $protocol."://" . $currenthost . $port; + } + + /** + * @param $host string The host to use when constructing URLs + */ + public static function setSelfHost($host) + { + self::$_host = $host; + } + + /** + * @param $baseurlpath string The baseurl path to use when constructing URLs + */ + public static function setBaseURLPath($baseurlpath) + { + if (empty($baseurlpath)) { + self::$_baseurlpath = null; + } else if ($baseurlpath == '/') { + self::$_baseurlpath = '/'; + } else { + self::$_baseurlpath = '/' . trim($baseurlpath, '/') . '/'; + } + } + + /** + * @return string The baseurlpath to be used when constructing URLs + */ + public static function getBaseURLPath() + { + return self::$_baseurlpath; + } + + /** + * @return string The raw host name + */ + protected static function getRawHost() + { + if (self::$_host) { + $currentHost = self::$_host; + } elseif (self::getProxyVars() && array_key_exists('HTTP_X_FORWARDED_HOST', $_SERVER)) { + $currentHost = explode(',', $_SERVER['HTTP_X_FORWARDED_HOST']); + $values = array_values($currentHost); + $currentHost = array_shift($values); + } elseif (array_key_exists('HTTP_HOST', $_SERVER)) { + $currentHost = $_SERVER['HTTP_HOST']; + } elseif (array_key_exists('SERVER_NAME', $_SERVER)) { + $currentHost = $_SERVER['SERVER_NAME']; + } else { + if (function_exists('gethostname')) { + $currentHost = gethostname(); + } else { + $currentHost = php_uname("n"); + } + } + return $currentHost; + } + + /** + * @param $port int The port number to use when constructing URLs + */ + public static function setSelfPort($port) + { + self::$_port = $port; + } + + /** + * @param $protocol string The protocol to identify as using, usually http or https + */ + public static function setSelfProtocol($protocol) + { + self::$_protocol = $protocol; + } + + /** + * @return string http|https + */ + public static function getSelfProtocol() + { + $protocol = 'http'; + if (self::$_protocol) { + $protocol = self::$_protocol; + } elseif (self::getSelfPort() == 443) { + $protocol = 'https'; + } elseif (self::getProxyVars() && isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) { + $protocol = $_SERVER['HTTP_X_FORWARDED_PROTO']; + } elseif (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') { + $protocol = 'https'; + } + return $protocol; + } + + /** + * Returns the current host. + * + * @return string $currentHost The current host + */ + public static function getSelfHost() + { + $currentHost = self::getRawHost(); + + // strip the port + if (false !== strpos($currentHost, ':')) { + list($currentHost, $port) = explode(':', $currentHost, 2); + } + + return $currentHost; + } + + /** + * @return null|string The port number used for the request + */ + public static function getSelfPort() + { + $portnumber = null; + if (self::$_port) { + $portnumber = self::$_port; + } else if (self::getProxyVars() && isset($_SERVER["HTTP_X_FORWARDED_PORT"])) { + $portnumber = $_SERVER["HTTP_X_FORWARDED_PORT"]; + } else if (isset($_SERVER["SERVER_PORT"])) { + $portnumber = $_SERVER["SERVER_PORT"]; + } else { + $currentHost = self::getRawHost(); + + // strip the port + if (false !== strpos($currentHost, ':')) { + list($currentHost, $port) = explode(':', $currentHost, 2); + if (is_numeric($port)) { + $portnumber = $port; + } + } + } + return $portnumber; + } + + /** + * Checks if https or http. + * + * @return bool $isHttps False if https is not active + */ + public static function isHTTPS() + { + return self::getSelfProtocol() == 'https'; + } + + /** + * Returns the URL of the current host + current view. + * + * @return string + */ + public static function getSelfURLNoQuery() + { + $selfURLNoQuery = self::getSelfURLhost(); + + $infoWithBaseURLPath = self::buildWithBaseURLPath($_SERVER['SCRIPT_NAME']); + if (!empty($infoWithBaseURLPath)) { + $selfURLNoQuery .= $infoWithBaseURLPath; + } else { + $selfURLNoQuery .= $_SERVER['SCRIPT_NAME']; + } + + if (isset($_SERVER['PATH_INFO'])) { + $selfURLNoQuery .= $_SERVER['PATH_INFO']; + } + + return $selfURLNoQuery; + } + + /** + * Returns the routed URL of the current host + current view. + * + * @return string + */ + public static function getSelfRoutedURLNoQuery() + { + $selfURLhost = self::getSelfURLhost(); + $route = ''; + + if (!empty($_SERVER['REQUEST_URI'])) { + $route = $_SERVER['REQUEST_URI']; + if (!empty($_SERVER['QUERY_STRING'])) { + $route = self::strLreplace($_SERVER['QUERY_STRING'], '', $route); + if (substr($route, -1) == '?') { + $route = substr($route, 0, -1); + } + } + } + + $infoWithBaseURLPath = self::buildWithBaseURLPath($route); + if (!empty($infoWithBaseURLPath)) { + $route = $infoWithBaseURLPath; + } + + $selfRoutedURLNoQuery = $selfURLhost . $route; + + $pos = strpos($selfRoutedURLNoQuery, "?"); + if ($pos !== false) { + $selfRoutedURLNoQuery = substr($selfRoutedURLNoQuery, 0, $pos); + } + + return $selfRoutedURLNoQuery; + } + + public static function strLreplace($search, $replace, $subject) + { + $pos = strrpos($subject, $search); + + if ($pos !== false) { + $subject = substr_replace($subject, $replace, $pos, strlen($search)); + } + + return $subject; + } + + /** + * Returns the URL of the current host + current view + query. + * + * @return string + */ + public static function getSelfURL() + { + $selfURLhost = self::getSelfURLhost(); + + $requestURI = ''; + if (!empty($_SERVER['REQUEST_URI'])) { + $requestURI = $_SERVER['REQUEST_URI']; + if ($requestURI[0] !== '/' && preg_match('#^https?://[^/]*(/.*)#i', $requestURI, $matches)) { + $requestURI = $matches[1]; + } + } + + $infoWithBaseURLPath = self::buildWithBaseURLPath($requestURI); + if (!empty($infoWithBaseURLPath)) { + $requestURI = $infoWithBaseURLPath; + } + + return $selfURLhost . $requestURI; + } + + /** + * Returns the part of the URL with the BaseURLPath. + * + * @param $info + * + * @return string + */ + protected static function buildWithBaseURLPath($info) + { + $result = ''; + $baseURLPath = self::getBaseURLPath(); + if (!empty($baseURLPath)) { + $result = $baseURLPath; + if (!empty($info)) { + $path = explode('/', $info); + $extractedInfo = array_pop($path); + if (!empty($extractedInfo)) { + $result .= $extractedInfo; + } + } + } + return $result; + } + + /** + * Extract a query param - as it was sent - from $_SERVER[QUERY_STRING] + * + * @param string $name The param to-be extracted + * + * @return string + */ + public static function extractOriginalQueryParam($name) + { + $index = strpos($_SERVER['QUERY_STRING'], $name.'='); + $substring = substr($_SERVER['QUERY_STRING'], $index + strlen($name) + 1); + $end = strpos($substring, '&'); + return $end ? substr($substring, 0, strpos($substring, '&')) : $substring; + } + + /** + * Generates an unique string (used for example as ID for assertions). + * + * @return string A unique string + */ + public static function generateUniqueID() + { + return 'ONELOGIN_' . sha1(uniqid((string)mt_rand(), true)); + } + + /** + * Converts a UNIX timestamp to SAML2 timestamp on the form + * yyyy-mm-ddThh:mm:ss(\.s+)?Z. + * + * @param string|int $time The time we should convert (DateTime). + * + * @return string $timestamp SAML2 timestamp. + */ + public static function parseTime2SAML($time) + { + $date = new DateTime("@$time", new DateTimeZone('UTC')); + $timestamp = $date->format("Y-m-d\TH:i:s\Z"); + return $timestamp; + } + + /** + * Converts a SAML2 timestamp on the form yyyy-mm-ddThh:mm:ss(\.s+)?Z + * to a UNIX timestamp. The sub-second part is ignored. + * + * @param string $time The time we should convert (SAML Timestamp). + * + * @return int $timestamp Converted to a unix timestamp. + * + * @throws Exception + */ + public static function parseSAML2Time($time) + { + $matches = array(); + + /* We use a very strict regex to parse the timestamp. */ + $exp1 = '/^(\\d\\d\\d\\d)-(\\d\\d)-(\\d\\d)'; + $exp2 = 'T(\\d\\d):(\\d\\d):(\\d\\d)(?:\\.\\d+)?Z$/D'; + if (preg_match($exp1 . $exp2, $time, $matches) == 0) { + throw new Exception( + 'Invalid SAML2 timestamp passed to' . + ' parseSAML2Time: ' . $time + ); + } + + /* Extract the different components of the time from the + * matches in the regex. int cast will ignore leading zeroes + * in the string. + */ + $year = (int)$matches[1]; + $month = (int)$matches[2]; + $day = (int)$matches[3]; + $hour = (int)$matches[4]; + $minute = (int)$matches[5]; + $second = (int)$matches[6]; + + /* We use gmmktime because the timestamp will always be given + * in UTC. + */ + $ts = gmmktime($hour, $minute, $second, $month, $day, $year); + + return $ts; + } + + + /** + * Interprets a ISO8601 duration value relative to a given timestamp. + * + * @param string $duration The duration, as a string. + * @param int|null $timestamp The unix timestamp we should apply the + * duration to. Optional, default to the + * current time. + * + * @return int The new timestamp, after the duration is applied. + * + * @throws Exception + */ + public static function parseDuration($duration, $timestamp = null) + { + assert('is_string($duration)'); + assert('is_null($timestamp) || is_int($timestamp)'); + + /* Parse the duration. We use a very strict pattern. */ + $durationRegEx = '#^(-?)P(?:(?:(?:(\\d+)Y)?(?:(\\d+)M)?(?:(\\d+)D)?(?:T(?:(\\d+)H)?(?:(\\d+)M)?(?:(\\d+)S)?)?)|(?:(\\d+)W))$#D'; + $matches = array(); + if (!preg_match($durationRegEx, $duration, $matches)) { + throw new Exception('Invalid ISO 8601 duration: ' . $duration); + } + + $durYears = (empty($matches[2]) ? 0 : (int)$matches[2]); + $durMonths = (empty($matches[3]) ? 0 : (int)$matches[3]); + $durDays = (empty($matches[4]) ? 0 : (int)$matches[4]); + $durHours = (empty($matches[5]) ? 0 : (int)$matches[5]); + $durMinutes = (empty($matches[6]) ? 0 : (int)$matches[6]); + $durSeconds = (empty($matches[7]) ? 0 : (int)$matches[7]); + $durWeeks = (empty($matches[8]) ? 0 : (int)$matches[8]); + + if (!empty($matches[1])) { + /* Negative */ + $durYears = -$durYears; + $durMonths = -$durMonths; + $durDays = -$durDays; + $durHours = -$durHours; + $durMinutes = -$durMinutes; + $durSeconds = -$durSeconds; + $durWeeks = -$durWeeks; + } + + if ($timestamp === null) { + $timestamp = time(); + } + + if ($durYears !== 0 || $durMonths !== 0) { + /* Special handling of months and years, since they aren't a specific interval, but + * instead depend on the current time. + */ + + /* We need the year and month from the timestamp. Unfortunately, PHP doesn't have the + * gmtime function. Instead we use the gmdate function, and split the result. + */ + $yearmonth = explode(':', gmdate('Y:n', $timestamp)); + $year = (int)$yearmonth[0]; + $month = (int)$yearmonth[1]; + + /* Remove the year and month from the timestamp. */ + $timestamp -= gmmktime(0, 0, 0, $month, 1, $year); + + /* Add years and months, and normalize the numbers afterwards. */ + $year += $durYears; + $month += $durMonths; + while ($month > 12) { + $year += 1; + $month -= 12; + } + while ($month < 1) { + $year -= 1; + $month += 12; + } + + /* Add year and month back into timestamp. */ + $timestamp += gmmktime(0, 0, 0, $month, 1, $year); + } + + /* Add the other elements. */ + $timestamp += $durWeeks * 7 * 24 * 60 * 60; + $timestamp += $durDays * 24 * 60 * 60; + $timestamp += $durHours * 60 * 60; + $timestamp += $durMinutes * 60; + $timestamp += $durSeconds; + + return $timestamp; + } + + /** + * Compares 2 dates and returns the earliest. + * + * @param string|null $cacheDuration The duration, as a string. + * @param string|int|null $validUntil The valid until date, as a string or as a timestamp + * + * @return int|null $expireTime The expiration time. + * + * @throws Exception + */ + public static function getExpireTime($cacheDuration = null, $validUntil = null) + { + $expireTime = null; + + if ($cacheDuration !== null) { + $expireTime = self::parseDuration($cacheDuration, time()); + } + + if ($validUntil !== null) { + if (is_int($validUntil)) { + $validUntilTime = $validUntil; + } else { + $validUntilTime = self::parseSAML2Time($validUntil); + } + if ($expireTime === null || $expireTime > $validUntilTime) { + $expireTime = $validUntilTime; + } + } + + return $expireTime; + } + + + /** + * Extracts nodes from the DOMDocument. + * + * @param DOMDocument $dom The DOMDocument + * @param string $query Xpath Expresion + * @param DomElement|null $context Context Node (DomElement) + * + * @return DOMNodeList The queried nodes + */ + public static function query($dom, $query, $context = null) + { + $xpath = new DOMXPath($dom); + $xpath->registerNamespace('samlp', OneLogin_Saml2_Constants::NS_SAMLP); + $xpath->registerNamespace('saml', OneLogin_Saml2_Constants::NS_SAML); + $xpath->registerNamespace('ds', OneLogin_Saml2_Constants::NS_DS); + $xpath->registerNamespace('xenc', OneLogin_Saml2_Constants::NS_XENC); + $xpath->registerNamespace('xsi', OneLogin_Saml2_Constants::NS_XSI); + $xpath->registerNamespace('xs', OneLogin_Saml2_Constants::NS_XS); + $xpath->registerNamespace('md', OneLogin_Saml2_Constants::NS_MD); + + if (isset($context)) { + $res = $xpath->query($query, $context); + } else { + $res = $xpath->query($query); + } + return $res; + } + + /** + * Checks if the session is started or not. + * + * @return bool true if the sessíon is started + */ + public static function isSessionStarted() + { + if (PHP_VERSION_ID >= 50400) { + return session_status() === PHP_SESSION_ACTIVE ? true : false; + } else { + return session_id() === '' ? false : true; + } + } + + /** + * Deletes the local session. + */ + public static function deleteLocalSession() + { + if (OneLogin_Saml2_Utils::isSessionStarted()) { + session_unset(); + session_destroy(); + } else { + $_SESSION = array(); + } + } + + /** + * Calculates the fingerprint of a x509cert. + * + * @param string $x509cert x509 cert + * @param string $alg + * + * @return null|string Formatted fingerprint + */ + public static function calculateX509Fingerprint($x509cert, $alg = 'sha1') + { + assert('is_string($x509cert)'); + + $arCert = explode("\n", $x509cert); + $data = ''; + $inData = false; + + foreach ($arCert as $curData) { + if (! $inData) { + if (strncmp($curData, '-----BEGIN CERTIFICATE', 22) == 0) { + $inData = true; + } elseif ((strncmp($curData, '-----BEGIN PUBLIC KEY', 21) == 0) || (strncmp($curData, '-----BEGIN RSA PRIVATE KEY', 26) == 0)) { + /* This isn't an X509 certificate. */ + return null; + } + } else { + if (strncmp($curData, '-----END CERTIFICATE', 20) == 0) { + break; + } + $data .= trim($curData); + } + } + + if (empty($data)) { + return null; + } + + $decodedData = base64_decode($data); + + switch ($alg) { + case 'sha512': + case 'sha384': + case 'sha256': + $fingerprint = hash($alg, $decodedData, false); + break; + case 'sha1': + default: + $fingerprint = strtolower(sha1($decodedData)); + break; + } + return $fingerprint; + } + + /** + * Formates a fingerprint. + * + * @param string $fingerprint fingerprint + * + * @return string Formatted fingerprint + */ + public static function formatFingerPrint($fingerprint) + { + $formatedFingerprint = str_replace(':', '', $fingerprint); + $formatedFingerprint = strtolower($formatedFingerprint); + return $formatedFingerprint; + } + + /** + * Generates a nameID. + * + * @param string $value fingerprint + * @param string $spnq SP Name Qualifier + * @param string|null $format SP Format + * @param string|null $cert IdP Public cert to encrypt the nameID + * @param string|null $nq IdP Name Qualifier + * + * @return string $nameIDElement DOMElement | XMLSec nameID + * + * @throws Exception + */ + public static function generateNameId($value, $spnq, $format = null, $cert = null, $nq = null) + { + + $doc = new DOMDocument(); + + $nameId = $doc->createElement('saml:NameID'); + if (isset($spnq)) { + $nameId->setAttribute('SPNameQualifier', $spnq); + } + if (isset($nq)) { + $nameId->setAttribute('NameQualifier', $nq); + } + if (isset($format)) { + $nameId->setAttribute('Format', $format); + } + $nameId->appendChild($doc->createTextNode($value)); + + $doc->appendChild($nameId); + + if (!empty($cert)) { + $seckey = new XMLSecurityKey(XMLSecurityKey::RSA_1_5, array('type'=>'public')); + $seckey->loadKey($cert); + + $enc = new XMLSecEnc(); + $enc->setNode($nameId); + $enc->type = XMLSecEnc::Element; + + $symmetricKey = new XMLSecurityKey(XMLSecurityKey::AES128_CBC); + $symmetricKey->generateSessionKey(); + $enc->encryptKey($seckey, $symmetricKey); + + $encryptedData = $enc->encryptNode($symmetricKey); + + $newdoc = new DOMDocument(); + + $encryptedID = $newdoc->createElement('saml:EncryptedID'); + + $newdoc->appendChild($encryptedID); + + $encryptedID->appendChild($encryptedID->ownerDocument->importNode($encryptedData, true)); + + return $newdoc->saveXML($encryptedID); + } else { + return $doc->saveXML($nameId); + } + } + + + /** + * Gets Status from a Response. + * + * @param DOMDocument $dom The Response as XML + * + * @return array $status The Status, an array with the code and a message. + * + * @throws OneLogin_Saml2_ValidationError + */ + public static function getStatus($dom) + { + $status = array(); + + $statusEntry = self::query($dom, '/samlp:Response/samlp:Status'); + if ($statusEntry->length != 1) { + throw new OneLogin_Saml2_ValidationError( + "Missing Status on response", + OneLogin_Saml2_ValidationError::MISSING_STATUS + ); + } + + $codeEntry = self::query($dom, '/samlp:Response/samlp:Status/samlp:StatusCode', $statusEntry->item(0)); + if ($codeEntry->length != 1) { + throw new OneLogin_Saml2_ValidationError( + "Missing Status Code on response", + OneLogin_Saml2_ValidationError::MISSING_STATUS_CODE + ); + } + $code = $codeEntry->item(0)->getAttribute('Value'); + $status['code'] = $code; + + $status['msg'] = ''; + $messageEntry = self::query($dom, '/samlp:Response/samlp:Status/samlp:StatusMessage', $statusEntry->item(0)); + if ($messageEntry->length == 0) { + $subCodeEntry = self::query($dom, '/samlp:Response/samlp:Status/samlp:StatusCode/samlp:StatusCode', $statusEntry->item(0)); + if ($subCodeEntry->length == 1) { + $status['msg'] = $subCodeEntry->item(0)->getAttribute('Value'); + } + } else if ($messageEntry->length == 1) { + $msg = $messageEntry->item(0)->textContent; + $status['msg'] = $msg; + } + + return $status; + } + + /** + * Decrypts an encrypted element. + * + * @param DOMElement $encryptedData The encrypted data. + * @param XMLSecurityKey $inputKey The decryption key. + * @param bool $formatOutput Format or not the output. + * + * @return DOMElement The decrypted element. + * + * @throws OneLogin_Saml2_ValidationError + */ + public static function decryptElement(DOMElement $encryptedData, XMLSecurityKey $inputKey, $formatOutput = true) + { + + $enc = new XMLSecEnc(); + + $enc->setNode($encryptedData); + $enc->type = $encryptedData->getAttribute("Type"); + + $symmetricKey = $enc->locateKey($encryptedData); + if (!$symmetricKey) { + throw new OneLogin_Saml2_ValidationError( + 'Could not locate key algorithm in encrypted data.', + OneLogin_Saml2_ValidationError::KEY_ALGORITHM_ERROR + ); + } + + $symmetricKeyInfo = $enc->locateKeyInfo($symmetricKey); + if (!$symmetricKeyInfo) { + throw new OneLogin_Saml2_ValidationError( + "Could not locate for the encrypted key.", + OneLogin_Saml2_ValidationError::KEYINFO_NOT_FOUND_IN_ENCRYPTED_DATA + ); + } + + $inputKeyAlgo = $inputKey->getAlgorithm(); + if ($symmetricKeyInfo->isEncrypted) { + $symKeyInfoAlgo = $symmetricKeyInfo->getAlgorithm(); + + if ($symKeyInfoAlgo === XMLSecurityKey::RSA_OAEP_MGF1P && $inputKeyAlgo === XMLSecurityKey::RSA_1_5) { + $inputKeyAlgo = XMLSecurityKey::RSA_OAEP_MGF1P; + } + + if ($inputKeyAlgo !== $symKeyInfoAlgo) { + throw new OneLogin_Saml2_ValidationError( + 'Algorithm mismatch between input key and key used to encrypt ' . + ' the symmetric key for the message. Key was: ' . + var_export($inputKeyAlgo, true) . '; message was: ' . + var_export($symKeyInfoAlgo, true), + OneLogin_Saml2_ValidationError::KEY_ALGORITHM_ERROR + ); + } + + $encKey = $symmetricKeyInfo->encryptedCtx; + $symmetricKeyInfo->key = $inputKey->key; + $keySize = $symmetricKey->getSymmetricKeySize(); + if ($keySize === null) { + // To protect against "key oracle" attacks + throw new OneLogin_Saml2_ValidationError( + 'Unknown key size for encryption algorithm: ' . var_export($symmetricKey->type, true), + OneLogin_Saml2_ValidationError::KEY_ALGORITHM_ERROR + ); + } + + $key = $encKey->decryptKey($symmetricKeyInfo); + if (strlen($key) != $keySize) { + $encryptedKey = $encKey->getCipherValue(); + $pkey = openssl_pkey_get_details($symmetricKeyInfo->key); + $pkey = sha1(serialize($pkey), true); + $key = sha1($encryptedKey . $pkey, true); + + /* Make sure that the key has the correct length. */ + if (strlen($key) > $keySize) { + $key = substr($key, 0, $keySize); + } elseif (strlen($key) < $keySize) { + $key = str_pad($key, $keySize); + } + } + $symmetricKey->loadKey($key); + } else { + $symKeyAlgo = $symmetricKey->getAlgorithm(); + if ($inputKeyAlgo !== $symKeyAlgo) { + throw new OneLogin_Saml2_ValidationError( + 'Algorithm mismatch between input key and key in message. ' . + 'Key was: ' . var_export($inputKeyAlgo, true) . '; message was: ' . + var_export($symKeyAlgo, true), + OneLogin_Saml2_ValidationError::KEY_ALGORITHM_ERROR + ); + } + $symmetricKey = $inputKey; + } + + $decrypted = $enc->decryptNode($symmetricKey, false); + + $xml = ''.$decrypted.''; + $newDoc = new DOMDocument(); + if ($formatOutput) { + $newDoc->preserveWhiteSpace = false; + $newDoc->formatOutput = true; + } + $newDoc = self::loadXML($newDoc, $xml); + if (!$newDoc) { + throw new OneLogin_Saml2_ValidationError( + 'Failed to parse decrypted XML.', + OneLogin_Saml2_ValidationError::INVALID_XML_FORMAT + ); + } + + $decryptedElement = $newDoc->firstChild->firstChild; + if ($decryptedElement === null) { + throw new OneLogin_Saml2_ValidationError( + 'Missing encrypted element.', + OneLogin_Saml2_ValidationError::MISSING_ENCRYPTED_ELEMENT + ); + } + + return $decryptedElement; + } + + /** + * Converts a XMLSecurityKey to the correct algorithm. + * + * @param XMLSecurityKey $key The key. + * @param string $algorithm The desired algorithm. + * @param string $type Public or private key, defaults to public. + * + * @return XMLSecurityKey The new key. + * + * @throws Exception + */ + public static function castKey(XMLSecurityKey $key, $algorithm, $type = 'public') + { + assert('is_string($algorithm)'); + assert('$type === "public" || $type === "private"'); + // do nothing if algorithm is already the type of the key + if ($key->type === $algorithm) { + return $key; + } + + if (!OneLogin_Saml2_Utils::isSupportedSigningAlgorithm($algorithm)) { + throw new Exception('Unsupported signing algorithm.'); + } + + $keyInfo = openssl_pkey_get_details($key->key); + if ($keyInfo === false) { + throw new Exception('Unable to get key details from XMLSecurityKey.'); + } + if (!isset($keyInfo['key'])) { + throw new Exception('Missing key in public key details.'); + } + $newKey = new XMLSecurityKey($algorithm, array('type'=>$type)); + $newKey->loadKey($keyInfo['key']); + return $newKey; + } + + /** + * @param $algorithm + * + * @return bool + */ + public static function isSupportedSigningAlgorithm($algorithm) + { + return in_array( + $algorithm, + array( + XMLSecurityKey::RSA_1_5, + XMLSecurityKey::RSA_SHA1, + XMLSecurityKey::RSA_SHA256, + XMLSecurityKey::RSA_SHA384, + XMLSecurityKey::RSA_SHA512 + ) + ); + } + + /** + * Adds signature key and senders certificate to an element (Message or Assertion). + * + * @param string|DomDocument $xml The element we should sign + * @param string $key The private key + * @param string $cert The public + * @param string $signAlgorithm Signature algorithm method + * @param string $digestAlgorithm Digest algorithm method + * + * @return string + * + * @throws Exception + */ + public static function addSign($xml, $key, $cert, $signAlgorithm = XMLSecurityKey::RSA_SHA1, $digestAlgorithm = XMLSecurityDSig::SHA1) + { + if ($xml instanceof DOMDocument) { + $dom = $xml; + } else { + $dom = new DOMDocument(); + $dom = self::loadXML($dom, $xml); + if (!$dom) { + throw new Exception('Error parsing xml string'); + } + } + + /* Load the private key. */ + $objKey = new XMLSecurityKey($signAlgorithm, array('type' => 'private')); + $objKey->loadKey($key, false); + + /* Get the EntityDescriptor node we should sign. */ + $rootNode = $dom->firstChild; + + /* Sign the metadata with our private key. */ + $objXMLSecDSig = new XMLSecurityDSig(); + $objXMLSecDSig->setCanonicalMethod(XMLSecurityDSig::EXC_C14N); + + $objXMLSecDSig->addReferenceList( + array($rootNode), + $digestAlgorithm, + array('http://www.w3.org/2000/09/xmldsig#enveloped-signature', XMLSecurityDSig::EXC_C14N), + array('id_name' => 'ID') + ); + + $objXMLSecDSig->sign($objKey); + + /* Add the certificate to the signature. */ + $objXMLSecDSig->add509Cert($cert, true); + + $insertBefore = $rootNode->firstChild; + $messageTypes = array('AuthnRequest', 'Response', 'LogoutRequest','LogoutResponse'); + if (in_array($rootNode->localName, $messageTypes)) { + $issuerNodes = self::query($dom, '/'.$rootNode->tagName.'/saml:Issuer'); + if ($issuerNodes->length == 1) { + $insertBefore = $issuerNodes->item(0)->nextSibling; + } + } + + /* Add the signature. */ + $objXMLSecDSig->insertSignature($rootNode, $insertBefore); + + /* Return the DOM tree as a string. */ + $signedxml = $dom->saveXML(); + + return $signedxml; + } + + /** + * Validates a signature (Message or Assertion). + * + * @param string|DomNode $xml The element we should validate + * @param string|null $cert The public cert + * @param string|null $fingerprint The fingerprint of the public cert + * @param string|null $fingerprintalg The algorithm used to get the fingerprint + * @param string|null $xpath The xpath of the signed element + * @param array|null $multiCerts Multiple public certs + * + * @return bool + * + * @throws Exception + */ + public static function validateSign($xml, $cert = null, $fingerprint = null, $fingerprintalg = 'sha1', $xpath = null, $multiCerts = null) + { + if ($xml instanceof DOMDocument) { + $dom = clone $xml; + } else if ($xml instanceof DOMElement) { + $dom = clone $xml->ownerDocument; + } else { + $dom = new DOMDocument(); + $dom = self::loadXML($dom, $xml); + } + + $objXMLSecDSig = new XMLSecurityDSig(); + $objXMLSecDSig->idKeys = array('ID'); + + if ($xpath) { + $nodeset = OneLogin_Saml2_Utils::query($dom, $xpath); + $objDSig = $nodeset->item(0); + $objXMLSecDSig->sigNode = $objDSig; + } else { + $objDSig = $objXMLSecDSig->locateSignature($dom); + } + + if (!$objDSig) { + throw new Exception('Cannot locate Signature Node'); + } + + $objKey = $objXMLSecDSig->locateKey(); + if (!$objKey) { + throw new Exception('We have no idea about the key'); + } + + if (!OneLogin_Saml2_Utils::isSupportedSigningAlgorithm($objKey->type)) { + throw new Exception('Unsupported signing algorithm.'); + } + + $objXMLSecDSig->canonicalizeSignedInfo(); + + try { + $retVal = $objXMLSecDSig->validateReference(); + } catch (Exception $e) { + throw $e; + } + + XMLSecEnc::staticLocateKeyInfo($objKey, $objDSig); + + if (!empty($multiCerts)) { + // If multiple certs are provided, I may ignore $cert and + // $fingerprint provided by the method and just check the + // certs on the array + $fingerprint = null; + } else { + // else I add the cert to the array in order to check + // validate signatures with it and the with it and the + // $fingerprint value + $multiCerts = array($cert); + } + + $valid = false; + foreach ($multiCerts as $cert) { + if (!empty($cert)) { + $objKey->loadKey($cert, false, true); + if ($objXMLSecDSig->verify($objKey) === 1) { + $valid = true; + break; + } + } else { + if (!empty($fingerprint)) { + $domCert = $objKey->getX509Certificate(); + $domCertFingerprint = OneLogin_Saml2_Utils::calculateX509Fingerprint($domCert, $fingerprintalg); + if (OneLogin_Saml2_Utils::formatFingerPrint($fingerprint) == $domCertFingerprint) { + $objKey->loadKey($domCert, false, true); + if ($objXMLSecDSig->verify($objKey) === 1) { + $valid = true; + break; + } + } + } + } + } + return $valid; + } + + /** + * Validates a binary signature + * + * @param string $messageType Type of SAML Message + * @param array $getData HTTP GET array + * @param array $idpData IdP setting data + * @param bool $retrieveParametersFromServer Indicates where to get the values in order to validate the Sign, from getData or from $_SERVER + * + * @return bool + * + * @throws Exception + */ + public static function validateBinarySign($messageType, $getData, $idpData, $retrieveParametersFromServer = false) + { + if (!isset($getData['SigAlg'])) { + $signAlg = XMLSecurityKey::RSA_SHA1; + } else { + $signAlg = $getData['SigAlg']; + } + + if ($retrieveParametersFromServer) { + $signedQuery = $messageType.'='.OneLogin_Saml2_Utils::extractOriginalQueryParam($messageType); + if (isset($getData['RelayState'])) { + $signedQuery .= '&RelayState='.OneLogin_Saml2_Utils::extractOriginalQueryParam('RelayState'); + } + $signedQuery .= '&SigAlg='.OneLogin_Saml2_Utils::extractOriginalQueryParam('SigAlg'); + } else { + $signedQuery = $messageType.'='.urlencode($getData[$messageType]); + if (isset($getData['RelayState'])) { + $signedQuery .= '&RelayState='.urlencode($getData['RelayState']); + } + $signedQuery .= '&SigAlg='.urlencode($signAlg); + } + + if ($messageType == "SAMLRequest") { + $strMessageType = "Logout Request"; + } else { + $strMessageType = "Logout Response"; + } + $existsMultiX509Sign = isset($idpData['x509certMulti']) && isset($idpData['x509certMulti']['signing']) && !empty($idpData['x509certMulti']['signing']); + if ((!isset($idpData['x509cert']) || empty($idpData['x509cert'])) && !$existsMultiX509Sign) { + throw new OneLogin_Saml2_Error( + "In order to validate the sign on the ".$strMessageType.", the x509cert of the IdP is required", + OneLogin_Saml2_Error::CERT_NOT_FOUND + ); + } + + if ($existsMultiX509Sign) { + $multiCerts = $idpData['x509certMulti']['signing']; + } else { + $multiCerts = array($idpData['x509cert']); + } + + $signatureValid = false; + foreach ($multiCerts as $cert) { + $objKey = new XMLSecurityKey(XMLSecurityKey::RSA_SHA1, array('type' => 'public')); + $objKey->loadKey($cert, false, true); + + if ($signAlg != XMLSecurityKey::RSA_SHA1) { + try { + $objKey = OneLogin_Saml2_Utils::castKey($objKey, $signAlg, 'public'); + } catch (Exception $e) { + $ex = new OneLogin_Saml2_ValidationError( + "Invalid signAlg in the received ".$strMessageType, + OneLogin_Saml2_ValidationError::INVALID_SIGNATURE + ); + if (count($multiCerts) == 1) { + throw $ex; + } + } + } + + if ($objKey->verifySignature($signedQuery, base64_decode($getData['Signature'])) === 1) { + $signatureValid = true; + break; + } + } + return $signatureValid; + } +} + diff --git a/docs/Saml2/font/FontAwesome.otf b/docs/Saml2/font/FontAwesome.otf new file mode 100644 index 00000000..3461e3fc Binary files /dev/null and b/docs/Saml2/font/FontAwesome.otf differ diff --git a/docs/Saml2/font/fontawesome-webfont.eot b/docs/Saml2/font/fontawesome-webfont.eot new file mode 100644 index 00000000..6cfd5660 Binary files /dev/null and b/docs/Saml2/font/fontawesome-webfont.eot differ diff --git a/docs/Saml2/font/fontawesome-webfont.svg b/docs/Saml2/font/fontawesome-webfont.svg new file mode 100644 index 00000000..a9f84695 --- /dev/null +++ b/docs/Saml2/font/fontawesome-webfont.svg @@ -0,0 +1,504 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/docs/Saml2/font/fontawesome-webfont.ttf b/docs/Saml2/font/fontawesome-webfont.ttf new file mode 100644 index 00000000..5cd6cff6 Binary files /dev/null and b/docs/Saml2/font/fontawesome-webfont.ttf differ diff --git a/docs/Saml2/font/fontawesome-webfont.woff b/docs/Saml2/font/fontawesome-webfont.woff new file mode 100644 index 00000000..9eaecb37 Binary files /dev/null and b/docs/Saml2/font/fontawesome-webfont.woff differ diff --git a/docs/Saml2/graphs/class.html b/docs/Saml2/graphs/class.html new file mode 100644 index 00000000..376f9404 --- /dev/null +++ b/docs/Saml2/graphs/class.html @@ -0,0 +1,163 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+ + +
+ + + diff --git a/docs/Saml2/graphs/classes.svg b/docs/Saml2/graphs/classes.svg new file mode 100644 index 00000000..e5845e87 --- /dev/null +++ b/docs/Saml2/graphs/classes.svg @@ -0,0 +1,108 @@ + + + + + + +G + + +cluster_Global + +Global + + + +\\OneLogin_Saml2_Settings + +OneLogin_Saml2_Settings + + + +\\OneLogin_Saml2_IdPMetadataParser + +OneLogin_Saml2_IdPMetadataParser + + + +\\OneLogin_Saml2_LogoutResponse + +OneLogin_Saml2_LogoutResponse + + + +\\OneLogin_Saml2_Constants + +OneLogin_Saml2_Constants + + + +\\OneLogin_Saml2_LogoutRequest + +OneLogin_Saml2_LogoutRequest + + + +\\OneLogin_Saml2_Error + +OneLogin_Saml2_Error + + + +\\Exception + +\Exception + + + +\\OneLogin_Saml2_Error->\\Exception + + + + + +\\OneLogin_Saml2_ValidationError + +OneLogin_Saml2_ValidationError + + + +\\OneLogin_Saml2_ValidationError->\\Exception + + + + + +\\OneLogin_Saml2_Utils + +OneLogin_Saml2_Utils + + + +\\OneLogin_Saml2_Auth + +OneLogin_Saml2_Auth + + + +\\OneLogin_Saml2_Response + +OneLogin_Saml2_Response + + + +\\OneLogin_Saml2_AuthnRequest + +OneLogin_Saml2_AuthnRequest + + + +\\OneLogin_Saml2_Metadata + +OneLogin_Saml2_Metadata + + + diff --git a/docs/Saml2/images/apple-touch-icon-114x114.png b/docs/Saml2/images/apple-touch-icon-114x114.png new file mode 100644 index 00000000..1506f6a6 Binary files /dev/null and b/docs/Saml2/images/apple-touch-icon-114x114.png differ diff --git a/docs/Saml2/images/apple-touch-icon-72x72.png b/docs/Saml2/images/apple-touch-icon-72x72.png new file mode 100644 index 00000000..d813259b Binary files /dev/null and b/docs/Saml2/images/apple-touch-icon-72x72.png differ diff --git a/docs/Saml2/images/apple-touch-icon.png b/docs/Saml2/images/apple-touch-icon.png new file mode 100644 index 00000000..2d320cb5 Binary files /dev/null and b/docs/Saml2/images/apple-touch-icon.png differ diff --git a/docs/Saml2/images/custom-icons.svg b/docs/Saml2/images/custom-icons.svg new file mode 100644 index 00000000..c6b8037f --- /dev/null +++ b/docs/Saml2/images/custom-icons.svg @@ -0,0 +1,116 @@ + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/docs/Saml2/images/favicon.ico b/docs/Saml2/images/favicon.ico new file mode 100644 index 00000000..9575ac8f Binary files /dev/null and b/docs/Saml2/images/favicon.ico differ diff --git a/docs/Saml2/images/hierarchy-item.png b/docs/Saml2/images/hierarchy-item.png new file mode 100644 index 00000000..c7756e75 Binary files /dev/null and b/docs/Saml2/images/hierarchy-item.png differ diff --git a/docs/Saml2/images/icon-class-13x13.png b/docs/Saml2/images/icon-class-13x13.png new file mode 100644 index 00000000..731f0bd3 Binary files /dev/null and b/docs/Saml2/images/icon-class-13x13.png differ diff --git a/docs/Saml2/images/icon-class.svg b/docs/Saml2/images/icon-class.svg new file mode 100644 index 00000000..7dacd0c7 --- /dev/null +++ b/docs/Saml2/images/icon-class.svg @@ -0,0 +1,77 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/docs/Saml2/images/icon-interface-13x13.png b/docs/Saml2/images/icon-interface-13x13.png new file mode 100644 index 00000000..aa24fa96 Binary files /dev/null and b/docs/Saml2/images/icon-interface-13x13.png differ diff --git a/docs/Saml2/images/icon-interface.svg b/docs/Saml2/images/icon-interface.svg new file mode 100644 index 00000000..7c6371ef --- /dev/null +++ b/docs/Saml2/images/icon-interface.svg @@ -0,0 +1,73 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/docs/Saml2/images/icon-trait-13x13.png b/docs/Saml2/images/icon-trait-13x13.png new file mode 100644 index 00000000..3c2792b1 Binary files /dev/null and b/docs/Saml2/images/icon-trait-13x13.png differ diff --git a/docs/Saml2/images/icon-trait.svg b/docs/Saml2/images/icon-trait.svg new file mode 100644 index 00000000..03cf08f4 --- /dev/null +++ b/docs/Saml2/images/icon-trait.svg @@ -0,0 +1,73 @@ + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + diff --git a/docs/Saml2/images/iviewer/grab.cur b/docs/Saml2/images/iviewer/grab.cur new file mode 100644 index 00000000..ef540be0 Binary files /dev/null and b/docs/Saml2/images/iviewer/grab.cur differ diff --git a/docs/Saml2/images/iviewer/hand.cur b/docs/Saml2/images/iviewer/hand.cur new file mode 100644 index 00000000..1a5bafb5 Binary files /dev/null and b/docs/Saml2/images/iviewer/hand.cur differ diff --git a/docs/Saml2/images/iviewer/iviewer.rotate_left.png b/docs/Saml2/images/iviewer/iviewer.rotate_left.png new file mode 100644 index 00000000..df0956de Binary files /dev/null and b/docs/Saml2/images/iviewer/iviewer.rotate_left.png differ diff --git a/docs/Saml2/images/iviewer/iviewer.rotate_right.png b/docs/Saml2/images/iviewer/iviewer.rotate_right.png new file mode 100644 index 00000000..7a6c8298 Binary files /dev/null and b/docs/Saml2/images/iviewer/iviewer.rotate_right.png differ diff --git a/docs/Saml2/images/iviewer/iviewer.zoom_fit.png b/docs/Saml2/images/iviewer/iviewer.zoom_fit.png new file mode 100644 index 00000000..364e01d9 Binary files /dev/null and b/docs/Saml2/images/iviewer/iviewer.zoom_fit.png differ diff --git a/docs/Saml2/images/iviewer/iviewer.zoom_in.png b/docs/Saml2/images/iviewer/iviewer.zoom_in.png new file mode 100644 index 00000000..78993327 Binary files /dev/null and b/docs/Saml2/images/iviewer/iviewer.zoom_in.png differ diff --git a/docs/Saml2/images/iviewer/iviewer.zoom_out.png b/docs/Saml2/images/iviewer/iviewer.zoom_out.png new file mode 100644 index 00000000..893f3502 Binary files /dev/null and b/docs/Saml2/images/iviewer/iviewer.zoom_out.png differ diff --git a/docs/Saml2/images/iviewer/iviewer.zoom_zero.png b/docs/Saml2/images/iviewer/iviewer.zoom_zero.png new file mode 100644 index 00000000..c981db6d Binary files /dev/null and b/docs/Saml2/images/iviewer/iviewer.zoom_zero.png differ diff --git a/docs/Saml2/index.html b/docs/Saml2/index.html new file mode 100644 index 00000000..028e3af4 --- /dev/null +++ b/docs/Saml2/index.html @@ -0,0 +1,244 @@ + + + + + + SAML PHP Toolkit + + + + + + + + + + + + + + + + + + + + + + + + + +
+
+ +
+
+
+
+
+ +

\

+ + + + +

Classes

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
OneLogin_Saml2_AuthMain class of PHP Toolkit
OneLogin_Saml2_AuthnRequestSAML 2 Authentication Request
OneLogin_Saml2_ConstantsConstants of PHP Toolkit
OneLogin_Saml2_ErrorError class of PHP Toolkit
OneLogin_Saml2_IdPMetadataParserIdP Metadata Parser of PHP Toolkit
OneLogin_Saml2_LogoutRequestSAML 2 Logout Request
OneLogin_Saml2_LogoutResponseSAML 2 Logout Response
OneLogin_Saml2_MetadataMetadata lib of PHP Toolkit
OneLogin_Saml2_ResponseSAML 2 Authentication Response
OneLogin_Saml2_SettingsConfiguration of the PHP Toolkit
OneLogin_Saml2_UtilsUtils of PHP Toolkit
OneLogin_Saml2_ValidationErrorThis class implements another custom Exception handler, +related to exceptions that happens during validation process.
+
+ + +
+ + + +
+
+ + +
+ + + diff --git a/docs/Saml2/js/bootstrap.min.js b/docs/Saml2/js/bootstrap.min.js new file mode 100644 index 00000000..319a85df --- /dev/null +++ b/docs/Saml2/js/bootstrap.min.js @@ -0,0 +1,7 @@ +/** +* Bootstrap.js by @fat & @mdo +* plugins: bootstrap-transition.js, bootstrap-modal.js, bootstrap-dropdown.js, bootstrap-scrollspy.js, bootstrap-tab.js, bootstrap-tooltip.js, bootstrap-popover.js, bootstrap-affix.js, bootstrap-alert.js, bootstrap-button.js, bootstrap-collapse.js, bootstrap-carousel.js, bootstrap-typeahead.js +* Copyright 2012 Twitter, Inc. +* http://www.apache.org/licenses/LICENSE-2.0.txt +*/ +!function(a){a(function(){a.support.transition=function(){var a=function(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"},c;for(c in b)if(a.style[c]!==undefined)return b[c]}();return a&&{end:a}}()})}(window.jQuery),!function(a){var b=function(b,c){this.options=c,this.$element=a(b).delegate('[data-dismiss="modal"]',"click.dismiss.modal",a.proxy(this.hide,this)),this.options.remote&&this.$element.find(".modal-body").load(this.options.remote)};b.prototype={constructor:b,toggle:function(){return this[this.isShown?"hide":"show"]()},show:function(){var b=this,c=a.Event("show");this.$element.trigger(c);if(this.isShown||c.isDefaultPrevented())return;this.isShown=!0,this.escape(),this.backdrop(function(){var c=a.support.transition&&b.$element.hasClass("fade");b.$element.parent().length||b.$element.appendTo(document.body),b.$element.show(),c&&b.$element[0].offsetWidth,b.$element.addClass("in").attr("aria-hidden",!1),b.enforceFocus(),c?b.$element.one(a.support.transition.end,function(){b.$element.focus().trigger("shown")}):b.$element.focus().trigger("shown")})},hide:function(b){b&&b.preventDefault();var c=this;b=a.Event("hide"),this.$element.trigger(b);if(!this.isShown||b.isDefaultPrevented())return;this.isShown=!1,this.escape(),a(document).off("focusin.modal"),this.$element.removeClass("in").attr("aria-hidden",!0),a.support.transition&&this.$element.hasClass("fade")?this.hideWithTransition():this.hideModal()},enforceFocus:function(){var b=this;a(document).on("focusin.modal",function(a){b.$element[0]!==a.target&&!b.$element.has(a.target).length&&b.$element.focus()})},escape:function(){var a=this;this.isShown&&this.options.keyboard?this.$element.on("keyup.dismiss.modal",function(b){b.which==27&&a.hide()}):this.isShown||this.$element.off("keyup.dismiss.modal")},hideWithTransition:function(){var b=this,c=setTimeout(function(){b.$element.off(a.support.transition.end),b.hideModal()},500);this.$element.one(a.support.transition.end,function(){clearTimeout(c),b.hideModal()})},hideModal:function(){var a=this;this.$element.hide(),this.backdrop(function(){a.removeBackdrop(),a.$element.trigger("hidden")})},removeBackdrop:function(){this.$backdrop&&this.$backdrop.remove(),this.$backdrop=null},backdrop:function(b){var c=this,d=this.$element.hasClass("fade")?"fade":"";if(this.isShown&&this.options.backdrop){var e=a.support.transition&&d;this.$backdrop=a('