simplesamlphp-1.14.0/0000755000000000000000000000000012660345162013156 5ustar rootrootsimplesamlphp-1.14.0/metadata-templates/0000755000000000000000000000000012660345056016734 5ustar rootrootsimplesamlphp-1.14.0/metadata-templates/adfs-idp-hosted.php0000644000000000000000000000045012660345056022417 0ustar rootroot '__DEFAULT__', 'privatekey' => 'server.pem', 'certificate' => 'server.crt', 'auth' => 'example-userpass', 'authproc' => array( // Convert LDAP names to WS-Fed Claims. 100 => array('class' => 'core:AttributeMap', 'name2claim'), ), ); simplesamlphp-1.14.0/metadata-templates/saml20-idp-hosted.php0000644000000000000000000000450612660345056022606 0ustar rootroot '__DEFAULT__', // X.509 key and certificate. Relative to the cert directory. 'privatekey' => 'server.pem', 'certificate' => 'server.crt', /* * Authentication source to use. Must be one that is configured in * 'config/authsources.php'. */ 'auth' => 'example-userpass', /* * WARNING: SHA-1 is disallowed starting January the 1st, 2014. * * Uncomment the following option to start using SHA-256 for your signatures. * Currently, SimpleSAMLphp defaults to SHA-1, which has been deprecated since * 2011, and will be disallowed by NIST as of 2014. Please refer to the following * document for more information: * * http://csrc.nist.gov/publications/nistpubs/800-131A/sp800-131A.pdf * * If you are uncertain about service providers supporting SHA-256 or other * algorithms of the SHA-2 family, you can configure it individually in the * SP-remote metadata set for those that support it. Once you are certain that * all your configured SPs support SHA-2, you can safely remove the configuration * options in the SP-remote metadata set and uncomment the following option. * * Please refer to the IdP hosted reference for more information. */ //'signature.algorithm' => 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', /* Uncomment the following to use the uri NameFormat on attributes. */ /* 'attributes.NameFormat' => 'urn:oasis:names:tc:SAML:2.0:attrname-format:uri', 'authproc' => array( // Convert LDAP names to oids. 100 => array('class' => 'core:AttributeMap', 'name2oid'), ), */ /* * Uncomment the following to specify the registration information in the * exported metadata. Refer to: * http://docs.oasis-open.org/security/saml/Post2.0/saml-metadata-rpi/v1.0/cs01/saml-metadata-rpi-v1.0-cs01.html * for more information. */ /* 'RegistrationInfo' => array( 'authority' => 'urn:mace:example.org', 'instant' => '2008-01-17T11:28:03Z', 'policies' => array( 'en' => 'http://example.org/policy', 'es' => 'http://example.org/politica', ), ), */ ); simplesamlphp-1.14.0/metadata-templates/shib13-idp-hosted.php0000644000000000000000000000115412660345056022575 0ustar rootroot '__DEFAULT__', // X.509 key and certificate. Relative to the cert directory. 'privatekey' => 'server.pem', 'certificate' => 'server.crt', /* * Authentication source to use. Must be one that is configured in * 'config/authsources.php'. */ 'auth' => 'example-userpass', ); simplesamlphp-1.14.0/metadata-templates/wsfed-idp-remote.php0000644000000000000000000000034112660345056022616 0ustar rootroot 'https://localhost:9031/idp/prp.wsf', 'certificate' => 'pingfed-localhost.pem', ); simplesamlphp-1.14.0/metadata-templates/shib13-sp-remote.php0000644000000000000000000000064212660345056022451 0ustar rootroot 'http://sp.shiblab.feide.no/Shibboleth.sso/SAML/POST', 'audience' => 'urn:mace:feide:shiblab', 'base64attributes' => FALSE, ); simplesamlphp-1.14.0/metadata-templates/adfs-sp-remote.php0000644000000000000000000000041412660345056022272 0ustar rootroot 'https://localhost/adfs/ls/', 'simplesaml.nameidattribute' => 'uid', 'authproc' => array( 50 => array( 'class' => 'core:AttributeLimit', 'cn', 'mail', 'uid', 'eduPersonAffiliation', ), ), ); simplesamlphp-1.14.0/metadata-templates/shib13-idp-remote.php0000644000000000000000000000063612660345056022606 0ustar rootroot 'https://idp.example.org/shibboleth-idp/SSO', 'certFingerprint' => 'c7279a9f28f11380509e072441e3dc55fb9ab864', ); */ simplesamlphp-1.14.0/metadata-templates/saml20-sp-remote.php0000644000000000000000000000224312660345056022455 0ustar rootroot 'https://saml2sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp', 'SingleLogoutService' => 'https://saml2sp.example.org/simplesaml/module.php/saml/sp/saml2-logout.php/default-sp', ); /* * This example shows an example config that works with Google Apps for education. * What is important is that you have an attribute in your IdP that maps to the local part of the email address * at Google Apps. In example, if your google account is foo.com, and you have a user that has an email john@foo.com, then you * must set the simplesaml.nameidattribute to be the name of an attribute that for this user has the value of 'john'. */ $metadata['google.com'] = array( 'AssertionConsumerService' => 'https://www.google.com/a/g.feide.no/acs', 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', 'simplesaml.nameidattribute' => 'uid', 'simplesaml.attributes' => FALSE, ); simplesamlphp-1.14.0/metadata-templates/shib13-sp-hosted.php0000644000000000000000000000035012660345056022440 0ustar rootroot '__DEFAULT__', ); simplesamlphp-1.14.0/metadata-templates/saml20-idp-remote.php0000644000000000000000000000166612660345056022617 0ustar rootroot array( 'en' => 'Feide OpenIdP - guest users', 'no' => 'Feide Gjestebrukere', ), 'description' => 'Here you can login with your account on Feide RnD OpenID. If you do not already have an account on this identity provider, you can create a new one by following the create new account link and follow the instructions.', 'SingleSignOnService' => 'https://openidp.feide.no/simplesaml/saml2/idp/SSOService.php', 'SingleLogoutService' => 'https://openidp.feide.no/simplesaml/saml2/idp/SingleLogoutService.php', 'certFingerprint' => 'c9ed4dfb07caf13fc21e0fec1572047eb8a7a4cb' ); simplesamlphp-1.14.0/metadata-templates/wsfed-sp-hosted.php0000644000000000000000000000024712660345056022464 0ustar rootroot '__DEFAULT__', ); simplesamlphp-1.14.0/LICENSE0000644000000000000000000005764712660345056014210 0ustar rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS simplesamlphp-1.14.0/CONTRIBUTE.md0000644000000000000000000001756112660345056015172 0ustar rootroot# Contribution guidelines **SimpleSAMLphp welcomes all contributions**. It is impossible to make a product like this without the efforts of many people, so please don't be shy and share your help with us. Even the tiniest contribution can make a difference! This guidelines briefly explain how to contribute to SimpleSAMLphp in an effective manner, making sure to keep high quality standards and making it easier for your contributions to make through. ## Team members Currently, the core team members are: * Jaime Pérez Crespo, *main developer and release manager*, UNINETT * Olav Morken, *main developer*, UNINETT * Andreas Åkre Solberg, *architect and original developer*, UNINETT We've been lucky to have the help of many people through the years. SimpleSAMLphp wouldn't have reached so far without them, and we want to thank them from here. Unfortunately, they are so many it is nearly impossible to mention all of them. [Github can offer a good summary on who has contributed to the project](https://github.com/simplesamlphp/simplesamlphp/graphs/contributors?from=2007-09-09&to=2015-09-06&type=c). Big thanks to you all! ## First things first Before embarking yourself in a contribution, please make sure you are familiar with the way SimpleSAMLphp is written, the way it works, and what is required or not. * Make sure to read [the documentation](https://simplesamlphp.org/docs/stable/). If you use the search engine in the website, please verify that you are reading the latest stable version. If you want to develop something, check [the development branch of the documentation](https://simplesamlphp.org/docs/development/). * If you have a question about **using SimpleSAMLphp**, please use [the mailing list](http://groups.google.com/group/simplesamlphp). * If you have a question about **developing SimpleSAMLphp**, please ask in the [development mailing list](http://groups.google.com/group/simplesamlphp-dev). * If you think you have discovered a bug, please check the [issue tracker](https://github.com/simplesamlphp/simplesamlphp/issues) and the [pull requests](https://github.com/simplesamlphp/simplesamlphp/pulls) to verify it hasn't been reported before. ## Contributing code New features are always welcome provided they will be useful to someone apart from yourself. Please take a look at the [list of issues](https://github.com/simplesamlphp/simplesamlphp/issues) to see what people is demanding. Our [roadmap](https://simplesamlphp.org/releaseplan) might also be a good place to start if you don't know exactly what you can contribute with. When contributing your code, please make sure to: * Respect the coding standards. We try to comply with PHP's [PSR-2](http://www.php-fig.org/psr/psr-2/). Pay special attention to: * Lines should not be longer than 80 characters. * Use **4 spaces** instead of tabs. * Keep the keywords in **lowercase**, including `true`, `false` and `null`. * Make sure your classes work with *autoloading*. * Never include a trailing `?>` in your files. * The first line of every file must be `process($request); return $request; } /* * Test the most basic functionality. */ public function testBasic() { $config = array( 'sourceAttribute' => 'eduPersonPrincipalName', 'targetAttribute' => 'scope', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('jdoe@example.com'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('scope', $attributes); $this->assertEquals($attributes['scope'], array('example.com')); } /* * If scope already set, module must not overwrite. */ public function testNoOverwrite() { $config = array( 'sourceAttribute' => 'eduPersonPrincipalName', 'targetAttribute' => 'scope', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('jdoe@example.com'), 'scope' => array('example.edu') ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['scope'], array('example.edu')); } /* * If source attribute not set, nothing happens */ public function testNoSourceAttribute() { $config = array( 'sourceAttribute' => 'eduPersonPrincipalName', 'targetAttribute' => 'scope', ); $request = array( 'Attributes' => array( 'mail' => array('j.doe@example.edu', 'john@example.org'), 'scope' => array('example.edu') ) ); $result = self::processFilter($config, $request); $this->assertEquals($request['Attributes'], $result['Attributes']); } /* * When multiple @ signs in attribute, should use last one. */ public function testMultiAt() { $config = array( 'sourceAttribute' => 'eduPersonPrincipalName', 'targetAttribute' => 'scope', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('john@doe@example.com'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['scope'], array('example.com')); } /* * When the source attribute doesn't have a scope, a warning is emitted * NOTE: currently disabled: this triggers a warning and a warning * wants to start a session which we cannot do in phpunit. How to fix? */ public function testNoAt() { $config = array( 'sourceAttribute' => 'eduPersonPrincipalName', 'targetAttribute' => 'scope', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('johndoe'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayNotHasKey('scope', $attributes); } } simplesamlphp-1.14.0/tests/modules/core/lib/Auth/Process/TargetedIDTest.php0000644000000000000000000001602112660345056025334 0ustar rootrootprocess($request); return $request; } // /** // * Test the most basic functionality // */ // public function testBasic() // { // $config = array( // ); // $request = array( // 'Attributes' => array(), // 'UserID' => 'user2@example.org', // ); // $result = self::processFilter($config, $request); // $attributes = $result['Attributes']; // $this->assertArrayHasKey('eduPersonTargetedID', $attributes); // $this->assertRegExp('/^[0-9a-f]{40}$/', $attributes['eduPersonTargetedID'][0]); // } // // /** // * Test with src and dst entityIds. // * Make sure to overwrite any present eduPersonTargetedId // */ // public function testWithSrcDst() // { // $config = array( // ); // $request = array( // 'Attributes' => array( // 'eduPersonTargetedID' => 'dummy', // ), // 'UserID' => 'user2@example.org', // 'Source' => array( // 'metadata-set' => 'saml20-idp-hosted', // 'entityid' => 'urn:example:src:id', // ), // 'Destination' => array( // 'metadata-set' => 'saml20-sp-remote', // 'entityid' => 'joe', // ), // ); // $result = self::processFilter($config, $request); // $attributes = $result['Attributes']; // $this->assertArrayHasKey('eduPersonTargetedID', $attributes); // $this->assertRegExp('/^[0-9a-f]{40}$/', $attributes['eduPersonTargetedID'][0]); // } // // /** // * Test with nameId config option set. // */ // public function testNameIdGeneration() // { // $config = array( // 'nameId' => true, // ); // $request = array( // 'Attributes' => array( // ), // 'UserID' => 'user2@example.org', // 'Source' => array( // 'metadata-set' => 'saml20-idp-hosted', // 'entityid' => 'urn:example:src:id', // ), // 'Destination' => array( // 'metadata-set' => 'saml20-sp-remote', // 'entityid' => 'joe', // ), // ); // $result = self::processFilter($config, $request); // $attributes = $result['Attributes']; // $this->assertArrayHasKey('eduPersonTargetedID', $attributes); // $this->assertRegExp('#^[0-9a-f]{40}$#', $attributes['eduPersonTargetedID'][0]); // } // // /** // * Test that Id is the same for subsequent invocations with same input. // */ // public function testIdIsPersistent() // { // $config = array( // ); // $request = array( // 'Attributes' => array( // 'eduPersonTargetedID' => 'dummy', // ), // 'UserID' => 'user2@example.org', // 'Source' => array( // 'metadata-set' => 'saml20-idp-hosted', // 'entityid' => 'urn:example:src:id', // ), // 'Destination' => array( // 'metadata-set' => 'saml20-sp-remote', // 'entityid' => 'joe', // ), // ); // for ($i = 0; $i < 10; ++$i) { // $result = self::processFilter($config, $request); // $attributes = $result['Attributes']; // $tid = $attributes['eduPersonTargetedID'][0]; // if (isset($prevtid)) { // $this->assertEquals($prevtid, $tid); // $prevtid = $tid; // } // } // } // // /** // * Test that Id is different for two different usernames and two different sp's // */ // public function testIdIsUnique() // { // $config = array( // ); // $request = array( // 'Attributes' => array( // ), // 'UserID' => 'user2@example.org', // 'Source' => array( // 'metadata-set' => 'saml20-idp-hosted', // 'entityid' => 'urn:example:src:id', // ), // 'Destination' => array( // 'metadata-set' => 'saml20-sp-remote', // 'entityid' => 'joe', // ), // ); // $result = self::processFilter($config, $request); // $tid1 = $result['Attributes']['eduPersonTargetedID'][0]; // // $request['UserID'] = 'user3@example.org'; // $result = self::processFilter($config, $request); // $tid2 = $result['Attributes']['eduPersonTargetedID'][0]; // // $this->assertNotEquals($tid1, $tid2); // // $request['Destination']['entityid'] = 'urn:example.org:another-sp'; // $result = self::processFilter($config, $request); // $tid3 = $result['Attributes']['eduPersonTargetedID'][0]; // // $this->assertNotEquals($tid2, $tid3); // } /** * Test no userid set * * @expectedException Exception */ public function testNoUserID() { $config = array( ); $request = array( 'Attributes' => array(), ); $result = self::processFilter($config, $request); } /** * Test with specified attribute not set * * @expectedException Exception */ public function testAttributeNotExists() { $config = array( 'attributename' => 'uid', ); $request = array( 'Attributes' => array( 'displayName' => 'Jack Student', ), ); $result = self::processFilter($config, $request); } /** * Test with configuration error 1 * * @expectedException Exception */ public function testConfigInvalidAttributeName() { $config = array( 'attributename' => 5, ); $request = array( 'Attributes' => array( 'displayName' => 'Jack Student', ), ); $result = self::processFilter($config, $request); } /** * Test with configuration error 2 * * @expectedException Exception */ public function testConfigInvalidNameId() { $config = array( 'nameId' => 'persistent', ); $request = array( 'Attributes' => array( 'displayName' => 'Jack Student', ), ); $result = self::processFilter($config, $request); } } simplesamlphp-1.14.0/tests/modules/core/lib/Auth/Process/ScopeAttributeTest.php0000644000000000000000000001573212660345056026325 0ustar rootrootprocess($request); return $request; } /* * Test the most basic functionality. */ public function testBasic() { $config = array( 'scopeAttribute' => 'eduPersonPrincipalName', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('jdoe@example.com'), 'eduPersonAffiliation' => array('member'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('eduPersonScopedAffiliation', $attributes); $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@example.com')); } /* * If target attribute already set, module must add, not overwrite. */ public function testNoOverwrite() { $config = array( 'scopeAttribute' => 'eduPersonPrincipalName', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('jdoe@example.com'), 'eduPersonAffiliation' => array('member'), 'eduPersonScopedAffiliation' => array('library-walk-in@example.edu'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('library-walk-in@example.edu', 'member@example.com')); } /* * If same scope already set, module must do nothing, not duplicate value. */ public function testNoDuplication() { $config = array( 'scopeAttribute' => 'eduPersonPrincipalName', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('jdoe@example.com'), 'eduPersonAffiliation' => array('member'), 'eduPersonScopedAffiliation' => array('member@example.com'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@example.com')); } /* * If source attribute not set, nothing happens */ public function testNoSourceAttribute() { $config = array( 'scopeAttribute' => 'eduPersonPrincipalName', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'mail' => array('j.doe@example.edu', 'john@example.org'), 'eduPersonAffiliation' => array('member'), 'eduPersonScopedAffiliation' => array('library-walk-in@example.edu'), ) ); $result = self::processFilter($config, $request); $this->assertEquals($request['Attributes'], $result['Attributes']); } /* * If scope attribute not set, nothing happens */ public function testNoScopeAttribute() { $config = array( 'scopeAttribute' => 'eduPersonPrincipalName', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'mail' => array('j.doe@example.edu', 'john@example.org'), 'eduPersonScopedAffiliation' => array('library-walk-in@example.edu'), 'eduPersonPrincipalName' => array('jdoe@example.com'), ) ); $result = self::processFilter($config, $request); $this->assertEquals($request['Attributes'], $result['Attributes']); } /* * When multiple @ signs in attribute, will use the first one. */ public function testMultiAt() { $config = array( 'scopeAttribute' => 'eduPersonPrincipalName', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('john@doe@example.com'), 'eduPersonAffiliation' => array('member'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@doe@example.com')); } /* * When multiple values in source attribute, should render multiple targets. */ public function testMultivaluedSource() { $config = array( 'scopeAttribute' => 'eduPersonPrincipalName', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'eduPersonPrincipalName' => array('jdoe@example.com'), 'eduPersonAffiliation' => array('member','staff','faculty'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('member@example.com','staff@example.com','faculty@example.com')); } /* * When the source attribute doesn't have a scope, the entire value is used. */ public function testNoAt() { $config = array( 'scopeAttribute' => 'schacHomeOrganization', 'sourceAttribute' => 'eduPersonAffiliation', 'targetAttribute' => 'eduPersonScopedAffiliation', ); $request = array( 'Attributes' => array( 'schacHomeOrganization' => array('example.org'), 'eduPersonAffiliation' => array('student'), ) ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['eduPersonScopedAffiliation'], array('student@example.org')); } } simplesamlphp-1.14.0/tests/modules/core/lib/Auth/Process/AttributeCopyTest.php0000644000000000000000000001013312660345056026154 0ustar rootrootprocess($request); return $request; } /** * Test the most basic functionality. */ public function testBasic() { $config = array( 'test' => 'testnew', ); $request = array( 'Attributes' => array('test' => array('AAP')), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('test', $attributes); $this->assertArrayHasKey('testnew', $attributes); $this->assertEquals($attributes['testnew'], array('AAP')); } /** * Test that existing attributes are left unmodified. */ public function testExistingNotModified() { $config = array( 'test' => 'testnew', ); $request = array( 'Attributes' => array( 'test' => array('AAP'), 'original1' => array('original_value1'), 'original2' => array('original_value2'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('testnew', $attributes); $this->assertEquals($attributes['test'], array('AAP')); $this->assertArrayHasKey('original1', $attributes); $this->assertEquals($attributes['original1'], array('original_value1')); $this->assertArrayHasKey('original2', $attributes); $this->assertEquals($attributes['original2'], array('original_value2')); } /** * Test copying multiple attributes */ public function testCopyMultiple() { $config = array( 'test1' => 'new1', 'test2' => 'new2', ); $request = array( 'Attributes' => array('test1' => array('val1'), 'test2' => array('val2.1','val2.2')), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('new1', $attributes); $this->assertEquals($attributes['new1'], array('val1')); $this->assertArrayHasKey('new2', $attributes); $this->assertEquals($attributes['new2'], array('val2.1','val2.2')); } /** * Test behaviour when target attribute exists (should be replaced). */ public function testCopyClash() { $config = array( 'test' => 'new1', ); $request = array( 'Attributes' => array( 'test' => array('testvalue1'), 'new1' => array('newvalue1'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['new1'], array('testvalue1')); } /** * Test wrong attribute name * * @expectedException Exception */ public function testWrongAttributeName() { $config = array( array('value2'), ); $request = array( 'Attributes' => array( 'test' => array('value1'), ), ); $result = self::processFilter($config, $request); } /** * Test wrong attribute value * * @expectedException Exception */ public function testWrongAttributeValue() { $config = array( 'test' => array('test2'), ); $request = array( 'Attributes' => array( 'test' => array('value1'), ), ); $result = self::processFilter($config, $request); } } simplesamlphp-1.14.0/tests/modules/core/lib/Auth/Process/AttributeAddTest.php0000644000000000000000000001171112660345056025735 0ustar rootrootprocess($request); return $request; } /** * Test the most basic functionality. */ public function testBasic() { $config = array( 'test' => array('value1', 'value2'), ); $request = array( 'Attributes' => array(), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('test', $attributes); $this->assertEquals($attributes['test'], array('value1', 'value2')); } /** * Test that existing attributes are left unmodified. */ public function testExistingNotModified() { $config = array( 'test' => array('value1', 'value2'), ); $request = array( 'Attributes' => array( 'original1' => array('original_value1'), 'original2' => array('original_value2'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('test', $attributes); $this->assertEquals($attributes['test'], array('value1', 'value2')); $this->assertArrayHasKey('original1', $attributes); $this->assertEquals($attributes['original1'], array('original_value1')); $this->assertArrayHasKey('original2', $attributes); $this->assertEquals($attributes['original2'], array('original_value2')); } /** * Test single string as attribute value. */ public function testStringValue() { $config = array( 'test' => 'value', ); $request = array( 'Attributes' => array(), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('test', $attributes); $this->assertEquals($attributes['test'], array('value')); } /** * Test adding multiple attributes in one config. */ public function testAddMultiple() { $config = array( 'test1' => array('value1'), 'test2' => array('value2'), ); $request = array( 'Attributes' => array(), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('test1', $attributes); $this->assertEquals($attributes['test1'], array('value1')); $this->assertArrayHasKey('test2', $attributes); $this->assertEquals($attributes['test2'], array('value2')); } /** * Test behavior when appending attribute values. */ public function testAppend() { $config = array( 'test' => array('value2'), ); $request = array( 'Attributes' => array( 'test' => array('value1'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['test'], array('value1', 'value2')); } /** * Test replacing attribute values. */ public function testReplace() { $config = array( '%replace', 'test' => array('value2'), ); $request = array( 'Attributes' => array( 'test' => array('value1'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['test'], array('value2')); } /** * Test wrong usage generates exceptions * * @expectedException Exception */ public function testWrongFlag() { $config = array( '%nonsense', 'test' => array('value2'), ); $request = array( 'Attributes' => array( 'test' => array('value1'), ), ); $result = self::processFilter($config, $request); } /** * Test wrong attribute value * * @expectedException Exception */ public function testWrongAttributeValue() { $config = array( '%replace', 'test' => array(true), ); $request = array( 'Attributes' => array( 'test' => array('value1'), ), ); $result = self::processFilter($config, $request); } } simplesamlphp-1.14.0/tests/modules/core/lib/Auth/Process/PHPTest.php0000644000000000000000000000251512660345056024012 0ustar rootrootprocess($request); return $request; } /** * Test the configuration of the filter. * * @expectedException SimpleSAML_Error_Exception */ public function testInvalidConfiguration() { $config = array(); new sspmod_core_Auth_Process_PHP($config, null); } /** * Check that defining the code works as expected. */ public function testCodeDefined() { $config = array( 'code' => ' $attributes["key"] = "value"; ', ); $request = array('Attributes' => array()); $expected = array( 'Attributes' => array( 'key' => 'value', ), ); $this->assertEquals($expected, $this->processFilter($config, $request)); } } simplesamlphp-1.14.0/tests/modules/core/lib/Auth/Process/AttributeRealmTest.php0000644000000000000000000000747712660345056026323 0ustar rootrootprocess($request); return $request; } /** * Test the most basic functionality. */ public function testBasic() { $config = array( ); $request = array( 'Attributes' => array(), 'UserID' => 'user2@example.org', ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('realm', $attributes); $this->assertEquals($attributes['realm'], array('example.org')); } /** * Test no userid set * * @expectedException Exception */ public function testNoUserID() { $config = array( ); $request = array( 'Attributes' => array(), ); $result = self::processFilter($config, $request); } /** * Test with configuration. */ public function testAttributeNameConfig() { $config = array( 'attributename' => 'schacHomeOrganization', ); $request = array( 'Attributes' => array( 'displayName' => 'Joe User', 'schacGender' => 9, ), 'UserID' => 'user2@example.org', ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('schacHomeOrganization', $attributes); $this->assertArrayHasKey('displayName', $attributes); $this->assertEquals($attributes['schacHomeOrganization'], array('example.org')); } /** * When target attribute exists it will be overwritten */ public function testTargetAttributeOverwritten() { $config = array( 'attributename' => 'schacHomeOrganization', ); $request = array( 'Attributes' => array( 'displayName' => 'Joe User', 'schacGender' => 9, 'schacHomeOrganization' => 'example.com', ), 'UserID' => 'user2@example.org', ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('schacHomeOrganization', $attributes); $this->assertEquals($attributes['schacHomeOrganization'], array('example.org')); } /** * When source attribute has no "@" no realm is added */ public function testNoAtisNoOp() { $config = array(); $request = array( 'Attributes' => array( 'displayName' => 'Joe User', ), 'UserID' => 'user2', ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayNotHasKey('realm', $attributes); } /** * When source attribute has more than one "@" no realm is added */ public function testMultiAtisNoOp() { $config = array(); $request = array( 'Attributes' => array( 'displayName' => 'Joe User', ), 'UserID' => 'user2@home@example.org', ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayNotHasKey('realm', $attributes); } } simplesamlphp-1.14.0/tests/modules/core/lib/Auth/Process/AttributeAlterTest.php0000644000000000000000000002316112660345056026316 0ustar rootrootprocess($request); return $request; } /** * Test the most basic functionality. */ public function testBasic() { $config = array( 'subject' => 'test', 'pattern' => '/wrong/', 'replacement' => 'right', ); $request = array( 'Attributes' => array( 'test' => array('somethingiswrong'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('test', $attributes); $this->assertEquals($attributes['test'], array('somethingisright')); } /** * Test the most basic functionality. */ public function testWithTarget() { $config = array( 'subject' => 'test', 'target' => 'test2', 'pattern' => '/wrong/', 'replacement' => 'right', ); $request = array( 'Attributes' => array( 'something' => array('somethingelse'), 'test' => array('wrong'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayHasKey('test2', $attributes); $this->assertEquals($attributes['test'], array('wrong')); $this->assertEquals($attributes['test2'], array('right')); } /** * Module is a no op if subject attribute is not present. */ public function testNomatch() { $config = array( 'subject' => 'test', 'pattern' => '/wrong/', 'replacement' => 'right', ); $request = array( 'Attributes' => array( 'something' => array('somevalue'), 'somethingelse' => array('someothervalue'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes, array('something' => array('somevalue'), 'somethingelse' => array('someothervalue'))); } /** * Test replacing attribute value. */ public function testReplaceMatch() { $config = array( 'subject' => 'source', 'pattern' => '/wrong/', 'replacement' => 'right', '%replace', ); $request = array( 'Attributes' => array( 'source' => array('wrongthing'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['source'], array('right')); } /** * Test replacing attribute value. */ public function testReplaceMatchWithTarget() { $config = array( 'subject' => 'source', 'pattern' => '/wrong/', 'replacement' => 'right', 'target' => 'test', '%replace', ); $request = array( 'Attributes' => array( 'source' => array('wrong'), 'test' => array('wrong'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['test'], array('right')); } /** * Test replacing attribute values. */ public function testReplaceNoMatch() { $config = array( 'subject' => 'test', 'pattern' => '/doink/', 'replacement' => 'wrong', 'target' => 'test', '%replace', ); $request = array( 'Attributes' => array( 'source' => array('wrong'), 'test' => array('right'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['test'], array('right')); } /** * Test removing attribute values. * Note that removing a value does not renumber the attributes array. * Also ensure unrelated attributes are not touched. */ public function testRemoveMatch() { $config = array( 'subject' => 'eduPersonAffiliation', 'pattern' => '/^emper/', '%remove', ); $request = array( 'Attributes' => array( 'displayName' => array('emperor kuzco'), 'eduPersonAffiliation' => array('member', 'emperor', 'staff'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertEquals($attributes['displayName'], array('emperor kuzco')); $this->assertEquals($attributes['eduPersonAffiliation'], array(0 => 'member', 2 => 'staff')); } /** * Test removing attribute values, resulting in an empty attribute. */ public function testRemoveMatchAll() { $config = array( 'subject' => 'eduPersonAffiliation', 'pattern' => '/^emper/', '%remove', ); $request = array( 'Attributes' => array( 'displayName' => array('emperor kuzco'), 'eduPersonAffiliation' => array('emperess', 'emperor'), ), ); $result = self::processFilter($config, $request); $attributes = $result['Attributes']; $this->assertArrayNotHasKey('eduPersonAffiliation', $attributes); } /** * Test for exception with illegal config. * * @expectedException Exception */ public function testWrongConfig() { $config = array( 'subject' => 'eduPersonAffiliation', 'pattern' => '/^emper/', '%dwiw', ); $request = array( 'Attributes' => array( 'eduPersonAffiliation' => array('emperess', 'emperor'), ), ); $result = self::processFilter($config, $request); } /** * Test for exception with illegal config. * * @expectedException Exception */ public function testIncompleteConfig() { $config = array( 'subject' => 'eduPersonAffiliation', ); $request = array( 'Attributes' => array( 'eduPersonAffiliation' => array('emperess', 'emperor'), ), ); $result = self::processFilter($config, $request); } /** * Test for exception with illegal config. * * @expectedException Exception */ public function testIncompleteConfig2() { $config = array( 'subject' => 'test', 'pattern' => '/wrong/', ); $request = array( 'Attributes' => array( 'test' => array('somethingiswrong'), ), ); $request = array( 'Attributes' => array( 'eduPersonAffiliation' => array('emperess', 'emperor'), ), ); $result = self::processFilter($config, $request); } /** * Test for exception with illegal config. * * @expectedException Exception */ public function testIncompleteConfig3() { $config = array( 'subject' => 'test', 'pattern' => '/wrong/', '%replace', '%remove', ); $request = array( 'Attributes' => array( 'test' => array('somethingiswrong'), ), ); $request = array( 'Attributes' => array( 'eduPersonAffiliation' => array('emperess', 'emperor'), ), ); $result = self::processFilter($config, $request); } /** * Test for exception with illegal config. * * @expectedException Exception */ public function testIncompleteConfig4() { $config = array( 'subject' => 'test', 'pattern' => '/wrong/', 'target' => 'test2', '%remove', ); $request = array( 'Attributes' => array( 'test' => array('somethingiswrong'), ), ); $request = array( 'Attributes' => array( 'eduPersonAffiliation' => array('emperess', 'emperor'), ), ); $result = self::processFilter($config, $request); } /** * Test for exception with illegal config. * * @expectedException Exception */ public function testIncompleteConfig5() { $config = array( 'subject' => 'test', 'pattern' => '/wrong/', 'replacement' => null, ); $request = array( 'Attributes' => array( 'test' => array('somethingiswrong'), ), ); $request = array( 'Attributes' => array( 'eduPersonAffiliation' => array('emperess', 'emperor'), ), ); $result = self::processFilter($config, $request); } } simplesamlphp-1.14.0/tests/lib/0000755000000000000000000000000012660345056015070 5ustar rootrootsimplesamlphp-1.14.0/tests/lib/SimpleSAML/0000755000000000000000000000000012660345056016776 5ustar rootrootsimplesamlphp-1.14.0/tests/lib/SimpleSAML/ConfigurationTest.php0000644000000000000000000004273512660345056023171 0ustar rootrootassertTrue(is_string($c->getVersion())); } /** * Test SimpleSAML_Configuration::getValue() */ public function testGetValue() { $c = SimpleSAML_Configuration::loadFromArray(array( 'exists_true' => TRUE, 'exists_null' => NULL, )); $this->assertEquals($c->getValue('missing'), NULL); $this->assertEquals($c->getValue('missing', TRUE), TRUE); $this->assertEquals($c->getValue('missing', TRUE), TRUE); $this->assertEquals($c->getValue('exists_true'), TRUE); $this->assertEquals($c->getValue('exists_null'), NULL); $this->assertEquals($c->getValue('exists_null', FALSE), NULL); } /** * Test SimpleSAML_Configuration::getValue(), REQUIRED_OPTION flag. * @expectedException Exception */ public function testGetValueRequired() { $c = SimpleSAML_Configuration::loadFromArray(array()); $c->getValue('missing', SimpleSAML_Configuration::REQUIRED_OPTION); } /** * Test SimpleSAML_Configuration::hasValue() */ public function testHasValue() { $c = SimpleSAML_Configuration::loadFromArray(array( 'exists_true' => TRUE, 'exists_null' => NULL, )); $this->assertEquals($c->hasValue('missing'), FALSE); $this->assertEquals($c->hasValue('exists_true'), TRUE); $this->assertEquals($c->hasValue('exists_null'), TRUE); } /** * Test SimpleSAML_Configuration::hasValue() */ public function testHasValueOneOf() { $c = SimpleSAML_Configuration::loadFromArray(array( 'exists_true' => TRUE, 'exists_null' => NULL, )); $this->assertEquals($c->hasValueOneOf(array()), FALSE); $this->assertEquals($c->hasValueOneOf(array('missing')), FALSE); $this->assertEquals($c->hasValueOneOf(array('exists_true')), TRUE); $this->assertEquals($c->hasValueOneOf(array('exists_null')), TRUE); $this->assertEquals($c->hasValueOneOf(array('missing1', 'missing2')), FALSE); $this->assertEquals($c->hasValueOneOf(array('exists_true', 'missing')), TRUE); $this->assertEquals($c->hasValueOneOf(array('missing', 'exists_true')), TRUE); } /** * Test SimpleSAML_Configuration::getBaseURL() */ public function testGetBaseURL() { $c = SimpleSAML_Configuration::loadFromArray(array()); $this->assertEquals($c->getBaseURL(), 'simplesaml/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => 'simplesaml/', )); $this->assertEquals($c->getBaseURL(), 'simplesaml/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => '/simplesaml/', )); $this->assertEquals($c->getBaseURL(), 'simplesaml/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => 'path/to/simplesaml/', )); $this->assertEquals($c->getBaseURL(), 'path/to/simplesaml/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => '/path/to/simplesaml/', )); $this->assertEquals($c->getBaseURL(), 'path/to/simplesaml/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => 'https://example.org/ssp/', )); $this->assertEquals($c->getBaseURL(), 'ssp/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => 'https://example.org/', )); $this->assertEquals($c->getBaseURL(), ''); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => 'http://example.org/ssp/', )); $this->assertEquals($c->getBaseURL(), 'ssp/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => '', )); $this->assertEquals($c->getBaseURL(), ''); $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => '/', )); $this->assertEquals($c->getBaseURL(), ''); } /** * Test that SimpleSAML_Configuration::getBaseURL() fails if given a path without trailing slash * @expectedException SimpleSAML_Error_Exception */ public function testGetBaseURLError() { $c = SimpleSAML_Configuration::loadFromArray(array( 'baseurlpath' => 'simplesaml', )); $c->getBaseURL(); } /** * Test SimpleSAML_Configuration::resolvePath() */ public function testResolvePath() { $c = SimpleSAML_Configuration::loadFromArray(array( 'basedir' => '/basedir/', )); $this->assertEquals($c->resolvePath(NULL), NULL); $this->assertEquals($c->resolvePath('/otherdir'), '/otherdir'); $this->assertEquals($c->resolvePath('relativedir'), '/basedir/relativedir'); $this->assertEquals($c->resolvePath('slash/'), '/basedir/slash'); $this->assertEquals($c->resolvePath('slash//'), '/basedir/slash'); } /** * Test SimpleSAML_Configuration::getPathValue() */ public function testGetPathValue() { $c = SimpleSAML_Configuration::loadFromArray(array( 'basedir' => '/basedir/', 'path_opt' => 'path', 'slashes_opt' => 'slashes//', )); $this->assertEquals($c->getPathValue('missing'), NULL); $this->assertEquals($c->getPathValue('path_opt'), '/basedir/path/'); $this->assertEquals($c->getPathValue('slashes_opt'), '/basedir/slashes/'); } /** * Test SimpleSAML_Configuration::getBaseDir() */ public function testGetBaseDir() { $c = SimpleSAML_Configuration::loadFromArray(array()); $this->assertEquals($c->getBaseDir(), dirname(dirname(dirname(dirname(__FILE__)))) . '/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'basedir' => '/basedir', )); $this->assertEquals($c->getBaseDir(), '/basedir/'); $c = SimpleSAML_Configuration::loadFromArray(array( 'basedir' => '/basedir/', )); $this->assertEquals($c->getBaseDir(), '/basedir/'); } /** * Test SimpleSAML_Configuration::getBoolean() */ public function testGetBoolean() { $c = SimpleSAML_Configuration::loadFromArray(array( 'true_opt' => TRUE, 'false_opt' => FALSE, )); $this->assertEquals($c->getBoolean('missing_opt', '--missing--'), '--missing--'); $this->assertEquals($c->getBoolean('true_opt', '--missing--'), TRUE); $this->assertEquals($c->getBoolean('false_opt', '--missing--'), FALSE); } /** * Test SimpleSAML_Configuration::getBoolean() missing option * @expectedException Exception */ public function testGetBooleanMissing() { $c = SimpleSAML_Configuration::loadFromArray(array()); $c->getBoolean('missing_opt'); } /** * Test SimpleSAML_Configuration::getBoolean() wrong option * @expectedException Exception */ public function testGetBooleanWrong() { $c = SimpleSAML_Configuration::loadFromArray(array( 'wrong' => 'true', )); $c->getBoolean('wrong'); } /** * Test SimpleSAML_Configuration::getString() */ public function testGetString() { $c = SimpleSAML_Configuration::loadFromArray(array( 'str_opt' => 'Hello World!', )); $this->assertEquals($c->getString('missing_opt', '--missing--'), '--missing--'); $this->assertEquals($c->getString('str_opt', '--missing--'), 'Hello World!'); } /** * Test SimpleSAML_Configuration::getString() missing option * @expectedException Exception */ public function testGetStringMissing() { $c = SimpleSAML_Configuration::loadFromArray(array()); $c->getString('missing_opt'); } /** * Test SimpleSAML_Configuration::getString() wrong option * @expectedException Exception */ public function testGetStringWrong() { $c = SimpleSAML_Configuration::loadFromArray(array( 'wrong' => FALSE, )); $c->getString('wrong'); } /** * Test SimpleSAML_Configuration::getInteger() */ public function testGetInteger() { $c = SimpleSAML_Configuration::loadFromArray(array( 'int_opt' => 42, )); $this->assertEquals($c->getInteger('missing_opt', '--missing--'), '--missing--'); $this->assertEquals($c->getInteger('int_opt', '--missing--'), 42); } /** * Test SimpleSAML_Configuration::getInteger() missing option * @expectedException Exception */ public function testGetIntegerMissing() { $c = SimpleSAML_Configuration::loadFromArray(array()); $c->getInteger('missing_opt'); } /** * Test SimpleSAML_Configuration::getInteger() wrong option * @expectedException Exception */ public function testGetIntegerWrong() { $c = SimpleSAML_Configuration::loadFromArray(array( 'wrong' => '42', )); $c->getInteger('wrong'); } /** * Test SimpleSAML_Configuration::getIntegerRange() */ public function testGetIntegerRange() { $c = SimpleSAML_Configuration::loadFromArray(array( 'int_opt' => 42, )); $this->assertEquals($c->getIntegerRange('missing_opt', 0, 100, '--missing--'), '--missing--'); $this->assertEquals($c->getIntegerRange('int_opt', 0, 100), 42); } /** * Test SimpleSAML_Configuration::getIntegerRange() below limit * @expectedException Exception */ public function testGetIntegerRangeBelow() { $c = SimpleSAML_Configuration::loadFromArray(array( 'int_opt' => 9, )); $this->assertEquals($c->getIntegerRange('int_opt', 10, 100), 42); } /** * Test SimpleSAML_Configuration::getIntegerRange() above limit * @expectedException Exception */ public function testGetIntegerRangeAbove() { $c = SimpleSAML_Configuration::loadFromArray(array( 'int_opt' => 101, )); $this->assertEquals($c->getIntegerRange('int_opt', 10, 100), 42); } /** * Test SimpleSAML_Configuration::getValueValidate() */ public function testGetValueValidate() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => 'b', )); $this->assertEquals($c->getValueValidate('missing_opt', array('a', 'b', 'c'), '--missing--'), '--missing--'); $this->assertEquals($c->getValueValidate('opt', array('a', 'b', 'c')), 'b'); } /** * Test SimpleSAML_Configuration::getValueValidate() wrong option * @expectedException Exception */ public function testGetValueValidateWrong() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => 'd', )); $c->getValueValidate('opt', array('a', 'b', 'c')); } /** * Test SimpleSAML_Configuration::getArray() */ public function testGetArray() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => array('a', 'b', 'c'), )); $this->assertEquals($c->getArray('missing_opt', '--missing--'), '--missing--'); $this->assertEquals($c->getArray('opt'), array('a', 'b', 'c')); } /** * Test SimpleSAML_Configuration::getArray() wrong option * @expectedException Exception */ public function testGetArrayWrong() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => 'not_an_array', )); $c->getArray('opt'); } /** * Test SimpleSAML_Configuration::getArrayize() */ public function testGetArrayize() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => array('a', 'b', 'c'), 'opt_int' => 42, 'opt_str' => 'string', )); $this->assertEquals($c->getArrayize('missing_opt', '--missing--'), '--missing--'); $this->assertEquals($c->getArrayize('opt'), array('a', 'b', 'c')); $this->assertEquals($c->getArrayize('opt_int'), array(42)); $this->assertEquals($c->getArrayize('opt_str'), array('string')); } /** * Test SimpleSAML_Configuration::getArrayizeString() */ public function testGetArrayizeString() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => array('a', 'b', 'c'), 'opt_str' => 'string', )); $this->assertEquals($c->getArrayizeString('missing_opt', '--missing--'), '--missing--'); $this->assertEquals($c->getArrayizeString('opt'), array('a', 'b', 'c')); $this->assertEquals($c->getArrayizeString('opt_str'), array('string')); } /** * Test SimpleSAML_Configuration::getArrayizeString() option with an array that contains something that isn't a string. * @expectedException Exception */ public function testGetArrayizeStringWrongValue() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => array('a', 'b', 42), )); $c->getArrayizeString('opt'); } /** * Test SimpleSAML_Configuration::getConfigItem() */ public function testGetConfigItem() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => array('a' => 42), )); $this->assertEquals($c->getConfigItem('missing_opt', '--missing--'), '--missing--'); $opt = $c->getConfigItem('opt'); $this->assertInstanceOf('SimpleSAML_Configuration', $opt); $this->assertEquals($opt->getValue('a'), 42); } /** * Test SimpleSAML_Configuration::getConfigItem() wrong option * @expectedException Exception */ public function testGetConfigItemWrong() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => 'not_an_array', )); $c->getConfigItem('opt'); } /** * Test SimpleSAML_Configuration::getConfigList() */ public function testGetConfigList() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opts' => array( 'a' => array('opt1' => 'value1'), 'b' => array('opt2' => 'value2'), ), )); $this->assertEquals($c->getConfigList('missing_opt', '--missing--'), '--missing--'); $opts = $c->getConfigList('opts'); $this->assertInternalType('array', $opts); $this->assertEquals(array_keys($opts), array('a', 'b')); $this->assertInstanceOf('SimpleSAML_Configuration', $opts['a']); $this->assertEquals($opts['a']->getValue('opt1'), 'value1'); $this->assertInstanceOf('SimpleSAML_Configuration', $opts['b']); $this->assertEquals($opts['b']->getValue('opt2'), 'value2'); } /** * Test SimpleSAML_Configuration::getConfigList() wrong option * @expectedException Exception */ public function testGetConfigListWrong() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => 'not_an_array', )); $c->getConfigList('opt'); } /** * Test SimpleSAML_Configuration::getOptions() */ public function testGetOptions() { $c = SimpleSAML_Configuration::loadFromArray(array( 'a' => TRUE, 'b' => NULL, )); $this->assertEquals($c->getOptions(), array('a', 'b')); } /** * Test SimpleSAML_Configuration::toArray() */ public function testToArray() { $c = SimpleSAML_Configuration::loadFromArray(array( 'a' => TRUE, 'b' => NULL, )); $this->assertEquals($c->toArray(), array('a' => TRUE, 'b' => NULL)); } /** * Test SimpleSAML_Configuration::getLocalizedString() */ public function testGetLocalizedString() { $c = SimpleSAML_Configuration::loadFromArray(array( 'str_opt' => 'Hello World!', 'str_array' => array( 'en' => 'Hello World!', 'no' => 'Hei Verden!', ), )); $this->assertEquals($c->getLocalizedString('missing_opt', '--missing--'), '--missing--'); $this->assertEquals($c->getLocalizedString('str_opt'), array('en' => 'Hello World!')); $this->assertEquals($c->getLocalizedString('str_array'), array('en' => 'Hello World!', 'no' => 'Hei Verden!')); } /** * Test SimpleSAML_Configuration::getLocalizedString() not array nor simple string * @expectedException Exception */ public function testGetLocalizedStringNotArray() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => 42, )); $c->getLocalizedString('opt'); } /** * Test SimpleSAML_Configuration::getLocalizedString() not string key * @expectedException Exception */ public function testGetLocalizedStringNotStringKey() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => array(42 => 'text'), )); $c->getLocalizedString('opt'); } /** * Test SimpleSAML_Configuration::getLocalizedString() not string value * @expectedException Exception */ public function testGetLocalizedStringNotStringValue() { $c = SimpleSAML_Configuration::loadFromArray(array( 'opt' => array('en' => 42), )); $c->getLocalizedString('opt'); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Auth/0000755000000000000000000000000012660345056017677 5ustar rootrootsimplesamlphp-1.14.0/tests/lib/SimpleSAML/Auth/StateTest.php0000644000000000000000000000472512660345056022340 0ustar rootroot array(), 'Expire' => 1234, 'LogoutState' => 'logoutState', 'AuthInstant' => 123456, 'RememberMe' => true, 'saml:sp:NameID' => 'nameID', ); // check just mandatory parameters $state = $mandatory; $expected = $mandatory; $this->assertEquals( $expected, SimpleSAML_Auth_State::getPersistentAuthData($state), 'Mandatory state attributes did not survive as expected'.print_r($expected, true) ); // check missing mandatory parameters unset($state['LogoutState']); unset($state['RememberMe']); $expected = $state; $this->assertEquals( $expected, SimpleSAML_Auth_State::getPersistentAuthData($state), 'Some error occurred with missing mandatory parameters' ); // check additional non-persistent parameters $additional = array( 'additional1' => 1, 'additional2' => 2, ); $state = array_merge($mandatory, $additional); $expected = $mandatory; $this->assertEquals( $expected, SimpleSAML_Auth_State::getPersistentAuthData($state), 'Additional parameters survived' ); // check additional persistent parameters $additional['PersistentAuthData'] = array('additional1'); $state = array_merge($mandatory, $additional); $expected = $state; unset($expected['additional2']); unset($expected['PersistentAuthData']); $this->assertEquals( $expected, SimpleSAML_Auth_State::getPersistentAuthData($state), 'Some error occurred with additional, persistent parameters' ); // check only additional persistent parameters $state = $additional; $expected = $state; unset($expected['additional2']); unset($expected['PersistentAuthData']); $this->assertEquals( $expected, SimpleSAML_Auth_State::getPersistentAuthData($state), 'Some error occurred with additional, persistent parameters, and no mandatory ones' ); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/DatabaseTest.php0000644000000000000000000002324312660345056022057 0ustar rootroot * @package SimpleSAMLphp */ class SimpleSAML_DatabaseTest extends PHPUnit_Framework_TestCase { /** * @var SimpleSAML_Configuration */ protected $config; /** * @var SimpleSAML\Database */ protected $db; /** * Make protected functions available for testing * * @param string $getMethod The method to get. * @requires PHP 5.3.2 * * @return mixed The method itself. */ protected static function getMethod($getMethod) { $class = new ReflectionClass('SimpleSAML\Database'); $method = $class->getMethod($getMethod); $method->setAccessible(true); return $method; } /** * @covers SimpleSAML\Database::getInstance * @covers SimpleSAML\Database::generateInstanceId * @covers SimpleSAML\Database::__construct * @covers SimpleSAML\Database::connect */ public function setUp() { $config = array( 'database.dsn' => 'sqlite::memory:', 'database.username' => null, 'database.password' => null, 'database.prefix' => 'phpunit_', 'database.persistent' => true, 'database.slaves' => array(), ); $this->config = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php"); // Ensure that we have a functional configuration class $this->assertInstanceOf('SimpleSAML_Configuration', $this->config); $this->assertEquals($config['database.dsn'], $this->config->getString('database.dsn')); $this->db = SimpleSAML\Database::getInstance($this->config); // Ensure that we have a functional database class. $this->assertInstanceOf('SimpleSAML\Database', $this->db); } /** * @covers SimpleSAML\Database::getInstance * @covers SimpleSAML\Database::generateInstanceId * @covers SimpleSAML\Database::__construct * @covers SimpleSAML\Database::connect * @expectedException Exception * @test */ public function connectionFailure() { $config = array( 'database.dsn' => 'mysql:host=localhost;dbname=saml', 'database.username' => 'notauser', 'database.password' => 'notausersinvalidpassword', 'database.prefix' => 'phpunit_', 'database.persistent' => true, 'database.slaves' => array(), ); $this->config = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php"); $db = SimpleSAML\Database::getInstance($this->config); } /** * @covers SimpleSAML\Database::getInstance * @covers SimpleSAML\Database::generateInstanceId * @covers SimpleSAML\Database::__construct * @covers SimpleSAML\Database::connect * @test */ public function instances() { $config = array( 'database.dsn' => 'sqlite::memory:', 'database.username' => null, 'database.password' => null, 'database.prefix' => 'phpunit_', 'database.persistent' => true, 'database.slaves' => array(), ); $config2 = array( 'database.dsn' => 'sqlite::memory:', 'database.username' => null, 'database.password' => null, 'database.prefix' => 'phpunit2_', 'database.persistent' => true, 'database.slaves' => array(), ); $config1 = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php"); $config2 = new SimpleSAML_Configuration($config2, "test/SimpleSAML/DatabaseTest.php"); $config3 = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php"); $db1 = SimpleSAML\Database::getInstance($config1); $db2 = SimpleSAML\Database::getInstance($config2); $db3 = SimpleSAML\Database::getInstance($config3); $generateInstanceId = self::getMethod('generateInstanceId'); $instance1 = $generateInstanceId->invokeArgs($db1, array($config1)); $instance2 = $generateInstanceId->invokeArgs($db2, array($config2)); $instance3 = $generateInstanceId->invokeArgs($db3, array($config3)); // Assert that $instance1 and $instance2 have different instance ids $this->assertNotEquals( $instance1, $instance2, "Database instances should be different, but returned the same id" ); // Assert that $instance1 and $instance3 have identical instance ids $this->assertEquals( $instance1, $instance3, "Database instances should have the same id, but returned different id" ); // Assert that $db1 and $db2 are different instances $this->assertNotEquals( spl_object_hash($db1), spl_object_hash($db2), "Database instances should be different, but returned the same spl_object_hash" ); // Assert that $db1 and $db3 are identical instances $this->assertEquals( spl_object_hash($db1), spl_object_hash($db3), "Database instances should be the same, but returned different spl_object_hash" ); } /** * @covers SimpleSAML\Database::getInstance * @covers SimpleSAML\Database::generateInstanceId * @covers SimpleSAML\Database::__construct * @covers SimpleSAML\Database::connect * @covers SimpleSAML\Database::getSlave * @test */ public function slaves() { $getSlave = self::getMethod('getSlave'); $master = spl_object_hash(PHPUnit_Framework_Assert::readAttribute($this->db, 'dbMaster')); $slave = spl_object_hash($getSlave->invokeArgs($this->db, array())); $this->assertTrue(($master == $slave), "getSlave should have returned the master database object"); $config = array( 'database.dsn' => 'sqlite::memory:', 'database.username' => null, 'database.password' => null, 'database.prefix' => 'phpunit_', 'database.persistent' => true, 'database.slaves' => array( array( 'dsn' => 'sqlite::memory:', 'username' => null, 'password' => null, ), ), ); $sspConfiguration = new SimpleSAML_Configuration($config, "test/SimpleSAML/DatabaseTest.php"); $msdb = SimpleSAML\Database::getInstance($sspConfiguration); $slaves = PHPUnit_Framework_Assert::readAttribute($msdb, 'dbSlaves'); $gotSlave = spl_object_hash($getSlave->invokeArgs($msdb, array())); $this->assertEquals( spl_object_hash($slaves[0]), $gotSlave, "getSlave should have returned a slave database object" ); } /** * @covers SimpleSAML\Database::applyPrefix * @test */ public function prefix() { $prefix = $this->config->getString('database.prefix'); $table = "saml20_idp_hosted"; $pftable = $this->db->applyPrefix($table); $this->assertEquals($prefix.$table, $pftable, "Did not properly apply the table prefix"); } /** * @covers SimpleSAML\Database::write * @covers SimpleSAML\Database::read * @covers SimpleSAML\Database::exec * @covers SimpleSAML\Database::query * @test */ public function querying() { $table = $this->db->applyPrefix("sspdbt"); $this->assertEquals($this->config->getString('database.prefix')."sspdbt", $table); $this->db->write( "CREATE TABLE IF NOT EXISTS $table (ssp_key INT(16) NOT NULL, ssp_value TEXT NOT NULL)", false ); $query1 = $this->db->read("SELECT * FROM $table"); $this->assertEquals(0, $query1->fetch(), "Table $table is not empty when it should be."); $ssp_key = time(); $ssp_value = md5(rand(0, 10000)); $stmt = $this->db->write( "INSERT INTO $table (ssp_key, ssp_value) VALUES (:ssp_key, :ssp_value)", array('ssp_key' => array($ssp_key, PDO::PARAM_INT), 'ssp_value' => $ssp_value) ); $this->assertEquals(1, $stmt->rowCount(), "Could not insert data into $table."); $query2 = $this->db->read("SELECT * FROM $table WHERE ssp_key = :ssp_key", array('ssp_key' => $ssp_key)); $data = $query2->fetch(); $this->assertEquals($data['ssp_value'], $ssp_value, "Inserted data doesn't match what is in the database"); } /** * @covers SimpleSAML\Database::read * @covers SimpleSAML\Database::query * @expectedException Exception * @test */ public function readFailure() { $table = $this->db->applyPrefix("sspdbt"); $this->assertEquals($this->config->getString('database.prefix')."sspdbt", $table); $this->db->read("SELECT * FROM $table"); } /** * @covers SimpleSAML\Database::write * @covers SimpleSAML\Database::exec * @expectedException Exception * @test */ public function noSuchTable() { $this->db->write("DROP TABLE phpunit_nonexistent", false); } public function tearDown() { $table = $this->db->applyPrefix("sspdbt"); $this->db->write("DROP TABLE IF EXISTS $table", false); unset($this->config); unset($this->db); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/0000755000000000000000000000000012660345056020076 5ustar rootrootsimplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/RandomTest.php0000644000000000000000000000067212660345056022674 0ustar rootrootassertStringStartsWith('_', SimpleSAML\Utils\Random::generateID()); // check the length $this->assertEquals(SimpleSAML\Utils\Random::ID_LENGTH, strlen(SimpleSAML\Utils\Random::generateID())); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/NetTest.php0000644000000000000000000000777412660345056022214 0ustar rootrootassertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0', '127.0.0.1')); // check wrong CIDR w/ mask $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.256/24', '127.0.0.1')); // check wrong IP $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/24', '127.0.0')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.*')); // check limits for standard classes $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.0')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.255')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/24', '127.0.0.256')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/16', '127.0.0.0')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/16', '127.0.255.255')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/16', '127.0.255.256')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/16', '127.0.256.255')); // check limits for non-standard classes $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/23', '127.0.0.0')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/23', '127.0.1.255')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/23', '127.0.1.256')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('127.0.0.0/23', '127.0.2.0')); } public function testIpv6CIDRcheck() { // check CIDR w/o mask $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::', '2001:0DB8::1')); // check wrong CIDR w/ mask $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/128', '2001:0DB8::1')); // check wrong IP $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/128', '2001:0DB8::Z')); // check limits for standard classes $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/128', '2001:0DB8:0000:0000:0000:0000:0000:0000')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/128', '2001:0DB8::0')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/128', '2001:0DB8::1')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/112', '2001:0DB8::1')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/112', '2001:0DB8::1:1')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/112', '2001:0DB8::FFFF')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/112', '2001:0DB8::1:FFFF')); // check limits for non-standard classes $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/108', '2001:0DB8::1:1')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/108', '2001:0DB8::F:1')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/108', '2001:0DB8::FF:1')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/108', '2001:0DB8::1FF:1')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/108', '2001:0DB8::FFFF:1')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/104', '2001:0DB8::1:1')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/104', '2001:0DB8::F:1')); $this->assertTrue(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/104', '2001:0DB8::FF:1')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/104', '2001:0DB8::1FF:1')); $this->assertFalse(SimpleSAML\Utils\Net::ipCIDRcheck('2001:0DB8::/104', '2001:0DB8::FFFF:1')); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/ArraysTest.php0000644000000000000000000000705012660345056022712 0ustar rootrootassertEquals($array, SimpleSAML\Utils\Arrays::arrayize($array)); // check non-empty array as input $array = array('key' => 'value'); $this->assertEquals($array, SimpleSAML\Utils\Arrays::arrayize($array)); // check indexes are ignored when input is an array $this->assertArrayNotHasKey('invalid', SimpleSAML\Utils\Arrays::arrayize($array, 'invalid')); // check default index $expected = array('string'); $this->assertEquals($expected, SimpleSAML\Utils\Arrays::arrayize($expected[0])); // check string index $index = 'key'; $expected = array($index => 'string'); $this->assertEquals($expected, SimpleSAML\Utils\Arrays::arrayize($expected[$index], $index)); } /** * Test the transpose() function. */ public function testTranspose() { // check bad arrays $this->assertFalse( SimpleSAML\Utils\Arrays::transpose(array('1', '2', '3')), 'Invalid two-dimensional array was accepted' ); $this->assertFalse( SimpleSAML\Utils\Arrays::transpose(array('1' => 0, '2' => '0', '3' => array(0))), 'Invalid elements on a two-dimensional array were accepted' ); // check array with numerical keys $array = array( 'key1' => array( 'value1' ), 'key2' => array( 'value1', 'value2' ) ); $transposed = array( array( 'key1' => 'value1', 'key2' => 'value1' ), array( 'key2' => 'value2' ) ); $this->assertEquals( $transposed, SimpleSAML\Utils\Arrays::transpose($array), 'Unexpected result of transpose()' ); // check array with string keys $array = array( 'key1' => array( 'subkey1' => 'value1' ), 'key2' => array( 'subkey1' => 'value1', 'subkey2' => 'value2' ) ); $transposed = array( 'subkey1' => array( 'key1' => 'value1', 'key2' => 'value1' ), 'subkey2' => array( 'key2' => 'value2' ) ); $this->assertEquals( $transposed, SimpleSAML\Utils\Arrays::transpose($array), 'Unexpected result of transpose()' ); // check array with no keys in common between sub arrays $array = array( 'key1' => array( 'subkey1' => 'value1' ), 'key2' => array( 'subkey2' => 'value1', 'subkey3' => 'value2' ) ); $transposed = array( 'subkey1' => array( 'key1' => 'value1', ), 'subkey2' => array( 'key2' => 'value1' ), 'subkey3' => array( 'key2' => 'value2' ) ); $this->assertEquals( $transposed, SimpleSAML\Utils\Arrays::transpose($array), 'Unexpected result of transpose()' ); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/ConfigTest.php0000644000000000000000000000276212660345056022663 0ustar rootrootassertEquals($configDir, dirname(dirname(dirname(dirname(__DIR__)))) . '/config'); } /** * Test valid dir specified by env var overrides default config dir */ public function testEnvVariableConfigDir() { putenv('SIMPLESAMLPHP_CONFIG_DIR=' . __DIR__); $configDir = \SimpleSAML\Utils\Config::getConfigDir(); $this->assertEquals($configDir, __DIR__); } /** * Test invalid dir specified by env var results in a thrown exception */ public function testInvalidEnvVariableConfigDirThrowsException() { // I used a random hash to ensure this test directory is always invalid $invalidDir = __DIR__ . '/e9826ad19cbc4f5bf20c0913ffcd2ce6'; putenv('SIMPLESAMLPHP_CONFIG_DIR=' . $invalidDir); $this->setExpectedException( 'InvalidArgumentException', 'Config directory specified by environment variable SIMPLESAMLPHP_CONFIG_DIR is not a directory. ' . 'Given: "' . $invalidDir . '"' ); \SimpleSAML\Utils\Config::getConfigDir(); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/Config/0000755000000000000000000000000012660345056021303 5ustar rootrootsimplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/Config/MetadataTest.php0000644000000000000000000001711712660345056024403 0ustar rootroot 'John Doe' ); try { $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertStringStartsWith('"contactType" is mandatory and must be one of ', $e->getMessage()); } // test invalid type $contact = array( 'contactType' => 'invalid' ); try { $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertStringStartsWith('"contactType" is mandatory and must be one of ', $e->getMessage()); } // test all valid contact types foreach (\SimpleSAML\Utils\Config\Metadata::$VALID_CONTACT_TYPES as $type) { $contact = array( 'contactType' => $type ); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayHasKey('contactType', $parsed); $this->assertArrayNotHasKey('givenName', $parsed); $this->assertArrayNotHasKey('surName', $parsed); } // test basic name parsing $contact = array( 'contactType' => 'technical', 'name' => 'John Doe' ); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayNotHasKey('name', $parsed); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayHasKey('surName', $parsed); $this->assertEquals('John', $parsed['givenName']); $this->assertEquals('Doe', $parsed['surName']); // test comma-separated names $contact = array( 'contactType' => 'technical', 'name' => 'Doe, John' ); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayHasKey('surName', $parsed); $this->assertEquals('John', $parsed['givenName']); $this->assertEquals('Doe', $parsed['surName']); // test long names $contact = array( 'contactType' => 'technical', 'name' => 'John Fitzgerald Doe Smith' ); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayNotHasKey('name', $parsed); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayNotHasKey('surName', $parsed); $this->assertEquals('John Fitzgerald Doe Smith', $parsed['givenName']); // test comma-separated long names $contact = array( 'contactType' => 'technical', 'name' => 'Doe Smith, John Fitzgerald' ); $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); $this->assertArrayNotHasKey('name', $parsed); $this->assertArrayHasKey('givenName', $parsed); $this->assertArrayHasKey('surName', $parsed); $this->assertEquals('John Fitzgerald', $parsed['givenName']); $this->assertEquals('Doe Smith', $parsed['surName']); // test givenName $contact = array( 'contactType' => 'technical', ); $invalid_types = array(0, array(0), 0.1, true, false); foreach ($invalid_types as $type) { $contact['givenName'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"givenName" must be a string and cannot be empty.', $e->getMessage()); } } // test surName $contact = array( 'contactType' => 'technical', ); $invalid_types = array(0, array(0), 0.1, true, false); foreach ($invalid_types as $type) { $contact['surName'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"surName" must be a string and cannot be empty.', $e->getMessage()); } } // test company $contact = array( 'contactType' => 'technical', ); $invalid_types = array(0, array(0), 0.1, true, false); foreach ($invalid_types as $type) { $contact['company'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('"company" must be a string and cannot be empty.', $e->getMessage()); } } // test emailAddress $contact = array( 'contactType' => 'technical', ); $invalid_types = array(0, 0.1, true, false, array()); foreach ($invalid_types as $type) { $contact['emailAddress'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals( '"emailAddress" must be a string or an array and cannot be empty.', $e->getMessage() ); } } $invalid_types = array(array("string", true), array("string", 0)); foreach ($invalid_types as $type) { $contact['emailAddress'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals( 'Email addresses must be a string and cannot be empty.', $e->getMessage() ); } } // test telephoneNumber $contact = array( 'contactType' => 'technical', ); $invalid_types = array(0, 0.1, true, false, array()); foreach ($invalid_types as $type) { $contact['telephoneNumber'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals( '"telephoneNumber" must be a string or an array and cannot be empty.', $e->getMessage() ); } } $invalid_types = array(array("string", true), array("string", 0)); foreach ($invalid_types as $type) { $contact['telephoneNumber'] = $type; try { \SimpleSAML\Utils\Config\Metadata::getContact($contact); } catch (InvalidArgumentException $e) { $this->assertEquals('Telephone numbers must be a string and cannot be empty.', $e->getMessage()); } } // test completeness $contact = array(); foreach (\SimpleSAML\Utils\Config\Metadata::$VALID_CONTACT_OPTIONS as $option) { $contact[$option] = 'string'; } $contact['contactType'] = 'technical'; $contact['name'] = 'to_be_removed'; $parsed = \SimpleSAML\Utils\Config\Metadata::getContact($contact); foreach (array_keys($parsed) as $key) { $this->assertEquals($parsed[$key], $contact[$key]); } $this->assertArrayNotHasKey('name', $parsed); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/CryptoTest.php0000644000000000000000000000450012660345056022726 0ustar rootrootsetAccessible(true); $m->invokeArgs(null, array(array(), 'SECRET')); } /** * Test invalid input provided to the aesEncrypt() method. * * @expectedException InvalidArgumentException */ public function testAesEncryptBadInput() { $m = new ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesEncrypt'); $m->setAccessible(true); $m->invokeArgs(null, array(array(), 'SECRET')); } /** * Test that aesDecrypt() works properly, being able to decrypt some previously known (and correct) * ciphertext. */ public function testAesDecrypt() { if (!extension_loaded('openssl')) { $this->setExpectedException('\SimpleSAML_Error_Exception'); } $secret = 'SUPER_SECRET_SALT'; $m = new ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesDecrypt'); $m->setAccessible(true); $plaintext = 'SUPER_SECRET_TEXT'; $ciphertext = 'NmRkODJlZGE2OTA3YTYwMm9En+KAReUk2z7Xi/b3c39kF/c1n6Vdj/zNARQt+UHU'; $this->assertEquals($plaintext, $m->invokeArgs(null, array(base64_decode($ciphertext), $secret))); } /** * Test that aesEncrypt() produces ciphertexts that aesDecrypt() can decrypt. */ public function testAesEncrypt() { if (!extension_loaded('openssl')) { $this->setExpectedException('\SimpleSAML_Error_Exception'); } $secret = 'SUPER_SECRET_SALT'; $e = new ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesEncrypt'); $d = new ReflectionMethod('\SimpleSAML\Utils\Crypto', '_aesDecrypt'); $e->setAccessible(true); $d->setAccessible(true); $original_plaintext = 'SUPER_SECRET_TEXT'; $ciphertext = $e->invokeArgs(null, array($original_plaintext, $secret)); $decrypted_plaintext = $d->invokeArgs(null, array($ciphertext, $secret)); $this->assertEquals($original_plaintext, $decrypted_plaintext); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Utils/AttributesTest.php0000644000000000000000000001373512660345056023606 0ustar rootroot */ class Utils_AttributesTest extends PHPUnit_Framework_TestCase { /** * Test the getExpectedAttribute() method with invalid attributes array. */ public function testGetExpectedAttributeInvalidAttributesArray() { // check with empty array as input $attributes = 'string'; $expected = 'string'; $this->setExpectedException( 'InvalidArgumentException', 'The attributes array is not an array, it is: '.print_r($attributes, true).'.' ); \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected); } /** * Test the getExpectedAttributeMethod() method with invalid expected attribute parameter. */ public function testGetExpectedAttributeInvalidAttributeName() { // check with invalid attribute name $attributes = array(); $expected = false; $this->setExpectedException( 'InvalidArgumentException', 'The expected attribute is not a string, it is: '.print_r($expected, true).'.' ); \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected); } /** * Test the getExpectedAttributeMethod() method with a non-normalized attributes array. */ public function testGetExpectedAttributeNonNormalizedArray() { // check with non-normalized attributes array $attributes = array( 'attribute' => 'value', ); $expected = 'attribute'; $this->setExpectedException( 'InvalidArgumentException', 'The attributes array is not normalized, values should be arrays.' ); \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected); } /** * Test the getExpectedAttribute() method with valid input but missing expected attribute. */ public function testGetExpectedAttributeMissingAttribute() { // check missing attribute $attributes = array( 'attribute' => array('value'), ); $expected = 'missing'; $this->setExpectedException( 'SimpleSAML_Error_Exception', "No such attribute '".$expected."' found." ); \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected); } /** * Test the getExpectedAttribute() method with an empty attribute. */ public function testGetExpectedAttributeEmptyAttribute() { // check empty attribute $attributes = array( 'attribute' => array(), ); $expected = 'attribute'; $this->setExpectedException( 'SimpleSAML_Error_Exception', "Empty attribute '".$expected."'.'" ); \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected); } /** * Test the getExpectedAttributeMethod() method with multiple values (not being allowed). */ public function testGetExpectedAttributeMultipleValues() { // check attribute with more than value, that being not allowed $attributes = array( 'attribute' => array( 'value1', 'value2', ), ); $expected = 'attribute'; $this->setExpectedException( 'SimpleSAML_Error_Exception', 'More than one value found for the attribute, multiple values not allowed.' ); \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected); } /** * Test that the getExpectedAttribute() method successfully obtains values from the attributes array. */ public function testGetExpectedAttribute() { // check one value $value = 'value'; $attributes = array( 'attribute' => array($value), ); $expected = 'attribute'; $this->assertEquals($value, \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected)); // check multiple (allowed) values $value = 'value'; $attributes = array( 'attribute' => array($value, 'value2', 'value3'), ); $expected = 'attribute'; $this->assertEquals($value, \SimpleSAML\Utils\Attributes::getExpectedAttribute($attributes, $expected, true)); } /** * Test the normalizeAttributesArray() function with input not being an array * * @expectedException InvalidArgumentException */ public function testNormalizeAttributesArrayBadInput() { SimpleSAML\Utils\Attributes::normalizeAttributesArray('string'); } /** * Test the normalizeAttributesArray() function with an array with non-string attribute names. * * @expectedException InvalidArgumentException */ public function testNormalizeAttributesArrayBadKeys() { SimpleSAML\Utils\Attributes::normalizeAttributesArray(array('attr1' => 'value1', 1 => 'value2')); } /** * Test the normalizeAttributesArray() function with an array with non-string attribute values. * * @expectedException InvalidArgumentException */ public function testNormalizeAttributesArrayBadValues() { SimpleSAML\Utils\Attributes::normalizeAttributesArray(array('attr1' => 'value1', 'attr2' => 0)); } /** * Test the normalizeAttributesArray() function. */ public function testNormalizeAttributesArray() { $attributes = array( 'key1' => 'value1', 'key2' => array('value2', 'value3'), 'key3' => 'value1' ); $expected = array( 'key1' => array('value1'), 'key2' => array('value2', 'value3'), 'key3' => array('value1') ); $this->assertEquals( $expected, SimpleSAML\Utils\Attributes::normalizeAttributesArray($attributes), 'Attribute array normalization failed' ); } } simplesamlphp-1.14.0/tests/lib/SimpleSAML/Metadata/0000755000000000000000000000000012660345056020516 5ustar rootrootsimplesamlphp-1.14.0/tests/lib/SimpleSAML/Metadata/SAMLBuilderTest.php0000644000000000000000000001363112660345056024136 0ustar rootroot $entityId, 'name' => array('en' => 'Test SP'), 'metadata-set' => $set, 'attributes' => array( 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10', 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6', 'urn:oid:0.9.2342.19200300.100.1.3', 'urn:oid:2.5.4.3', ), ); $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId); $samlBuilder->addMetadata($set, $metadata); $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); for ($c = 0; $c < $attributes->length; $c++) { $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertFalse($curAttribute->hasAttribute("FriendlyName")); $this->assertEquals($metadata['attributes'][$c], $curAttribute->getAttribute("Name")); } // test SP20 array parsing, no friendly name $set = 'saml20-sp-remote'; $metadata = array( 'entityid' => $entityId, 'name' => array('en' => 'Test SP'), 'metadata-set' => $set, 'attributes' => array( 'eduPersonTargetedID' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10', 'eduPersonPrincipalName' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6', 'eduPersonOrgDN' => 'urn:oid:0.9.2342.19200300.100.1.3', 'cn' => 'urn:oid:2.5.4.3', ), ); $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId); $samlBuilder->addMetadata($set, $metadata); $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); $keys = array_keys($metadata['attributes']); for ($c = 0; $c < $attributes->length; $c++) { $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertTrue($curAttribute->hasAttribute("FriendlyName")); $this->assertEquals($metadata['attributes'][$keys[$c]], $curAttribute->getAttribute("Name")); $this->assertEquals($keys[$c], $curAttribute->getAttribute("FriendlyName")); } // test SP13 array parsing, no friendly name $set = 'shib13-sp-remote'; $metadata = array( 'entityid' => $entityId, 'name' => array('en' => 'Test SP'), 'metadata-set' => $set, 'attributes' => array( 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10', 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6', 'urn:oid:0.9.2342.19200300.100.1.3', 'urn:oid:2.5.4.3', ), ); $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId); $samlBuilder->addMetadata($set, $metadata); $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); for ($c = 0; $c < $attributes->length; $c++) { $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertFalse($curAttribute->hasAttribute("FriendlyName")); $this->assertEquals($metadata['attributes'][$c], $curAttribute->getAttribute("Name")); } // test SP20 array parsing, no friendly name $set = 'shib13-sp-remote'; $metadata = array( 'entityid' => $entityId, 'name' => array('en' => 'Test SP'), 'metadata-set' => $set, 'attributes' => array( 'eduPersonTargetedID' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.10', 'eduPersonPrincipalName' => 'urn:oid:1.3.6.1.4.1.5923.1.1.1.6', 'eduPersonOrgDN' => 'urn:oid:0.9.2342.19200300.100.1.3', 'cn' => 'urn:oid:2.5.4.3', ), ); $samlBuilder = new SimpleSAML_Metadata_SAMLBuilder($entityId); $samlBuilder->addMetadata($set, $metadata); $spDesc = $samlBuilder->getEntityDescriptor(); $acs = $spDesc->getElementsByTagName("AttributeConsumingService"); $this->assertEquals(1, $acs->length); $attributes = $acs->item(0)->getElementsByTagName("RequestedAttribute"); $this->assertEquals(4, $attributes->length); $keys = array_keys($metadata['attributes']); for ($c = 0; $c < $attributes->length; $c++) { $curAttribute = $attributes->item($c); $this->assertTrue($curAttribute->hasAttribute("Name")); $this->assertTrue($curAttribute->hasAttribute("FriendlyName")); $this->assertEquals($metadata['attributes'][$keys[$c]], $curAttribute->getAttribute("Name")); $this->assertEquals($keys[$c], $curAttribute->getAttribute("FriendlyName")); } } } simplesamlphp-1.14.0/docs/0000755000000000000000000000000012660345056014110 5ustar rootrootsimplesamlphp-1.14.0/docs/simplesamlphp-upgrade-notes-1.13.txt0000644000000000000000000000104012660345056022655 0ustar rootrootUpgrade notes for SimpleSAMLphp 1.13 ==================================== * The RSA_1.5 (RSA with PKCS#1 v1.5 padding) algorithm is now longer allowed by default. This means messages received that use this algorithm will fail to decrypt. * Several functions, classes and interfaces are now deprecated. Please check your code if you are using the API. * A workaround related to performance issues when processing large metadata sets was included in **1.13.2**. **This workaround is experimental and could have unexpected side effects**.simplesamlphp-1.14.0/docs/simplesamlphp-automated_metadata.txt0000644000000000000000000002367512660345056023365 0ustar rootrootAutomated Metadata Management ============================= Introduction ------------ If you want to connect an Identity Provider, or a Service Provider to a **federation**, you need to setup metadata for the entries that you trust. In many federations, in particular federations based upon the Shibboleth software, it is normal to setup automated distribution of metadata using the SAML 2.0 Metadata XML Format. Some central administration or authority, provides a URL with a SAML 2.0 document including metadata for all entities in the federation. The present document explains how to setup automated downloading and parsing of a metadata document on a specific URL. Preparations ------------ You need to enable the following modules: 1. cron 2. metarefresh The cron module allows you to do tasks regularly, by setting up a cron job that calls a hook in SimpleSAMLphp. The metarefresh module will download and parse the metadata document and store it in metadata files cached locally. First, you will need to copy the `config-templates` files of the two modules above into the global `config/` directory. [root@simplesamlphp] cd /var/simplesamlphp [root@simplesamlphp simplesamlphp] touch modules/cron/enable [root@simplesamlphp simplesamlphp] cp modules/cron/config-templates/*.php config/ [root@simplesamlphp simplesamlphp] touch modules/metarefresh/enable [root@simplesamlphp simplesamlphp] cp modules/metarefresh/config-templates/*.php config/ Testing it manually ------------------- It is often useful to verify that the metadata sources we want to use can be parsed and verified by metarefresh, before actually configuring it. We can do so in the command line, by invoking metarefresh with the URL of the metadata set we want to check. For instance, if we want to configure the metadata of the SWITCH AAI Test Federation: cd modules/metarefresh/bin ./metarefresh.php -s http://metadata.aai.switch.ch/metadata.aaitest.xml The `-s` option sends the output to the console (for testing purposes). If the output makes sense, continue. If you get a lot of error messages, try to read them and fix the problems that might be causing them. If you are having problems and you can't figure out the cause, you can always send an e-mail to the SimpleSAMLphp mailing list and ask for advice. Configuring the metarefresh module ---------------------------------- Now we are going to proceed to configure the metarefresh module. First, edit the appropriate configuration file: [root@simplesamlphp simplesamlphp]# vi config/config-metarefresh.php Here's an example of a possible configuration for both the Kalmar Federation and UK Access Management Federation: $config = array( 'sets' => array( 'kalmar' => array( 'cron' => array('hourly'), 'sources' => array( array( 'src' => 'https://kalmar.feide.no/simplesaml/module.php/aggregator/?id=kalmarcentral&mimetype=text/plain&exclude=norway', 'certificates' => array( 'current.crt', 'rollover.crt', ), 'template' => array( 'tags' => array('kalmar'), 'authproc' => array( 51 => array('class' => 'core:AttributeMap', 'oid2name'), ), ), ), ), 'expireAfter' => 60*60*24*4, // Maximum 4 days cache time. 'outputDir' => 'metadata/metarefresh-kalmar/', 'outputFormat' => 'flatfile', ), 'uk' => array( 'cron' => array('hourly'), 'sources' => array( array( 'src' => 'http://metadata.ukfederation.org.uk/ukfederation-metadata.xml', 'validateFingerprint' => 'D0:E8:40:25:F0:B1:2A:CC:74:22:ED:C3:87:04:BC:29:BB:7B:9A:40', ), ), 'expireAfter' => 60*60*24*4, // Maximum 4 days cache time. 'outputDir' => 'metadata/metarefresh-ukaccess/', 'outputFormat' => 'serialize', ), ) ); The configuration consists of one or more metadata sets. Each metadata set has its own configuration, representing a metadata set of sources. Some federations will provide you with detailed instructions on how to configure metarefresh to fetch their metadata automatically, like, for instance, [the InCommon federation in the US](https://spaces.internet2.edu/x/eYHFAg). Whenever a federation provides you with specific instructions to configure metarefresh, be sure to use them from the authoritative source. The metarefresh module supports the following configuration options: `cron` : Which cron tags will refresh this metadata set. `sources` : An array of metadata sources that will be included in this metadata set. The contents of this option will be described later in more detail. `expireAfter` : The maximum number of seconds a metadata entry will be valid. `outputDir` : The directory where the generated metadata will be stored. The path is relative to the SimpleSAMLphp base directory. `outputFormat` : The format of the generated metadata files. This must match the metadata source added in `config.php`. `types` : The sets of entities to load. An array containing strings identifying the different types of entities that will be loaded. Valid types are: * saml20-idp-remote * saml20-sp-remote * shib13-idp-remote * shib13-sp-remote * attributeauthority-remote All entity types will be loaded by default. Each metadata source has the following options: `src` : The source URL where the metadata will be fetched from. `certificates` : An array of certificate files, the filename is relative to the `cert/`-directory, that will be used to verify the signature of the metadata. The public key will be extracted from the certificate and everything else will be ignored. So it is possible to use a self signed certificate that has expired. Add more than one certificate to be able to handle key rollover. This takes precedence over validateFingerprint. `validateFingerprint` : The fingerprint of the certificate used to sign the metadata. You don't need this option if you don't want to validate the signature on the metadata. `template` : This is an array which will be combined with the metadata fetched to generate the final metadata array. `types` : Same as the option with the same name at the metadata set level. This option has precedence when both are specified, allowing a more fine grained configuration for every metadata source. After you have configured the metadata sources, you need to give the web-server write access to the output directories. Following the previous example: chown www-data /var/simplesamlphp/metadata/metarefresh-kalmar/ chown www-data /var/simplesamlphp/metadata/metarefresh-ukaccess/ Now you can configure SimpleSAMLphp to use the metadata fetched by metarefresh. Edit the main config.php file, and modify the `metadata.sources` directive accordingly: 'metadata.sources' => array( array('type' => 'flatfile'), array('type' => 'flatfile', 'directory' => 'metadata/metarefresh-kalmar'), array('type' => 'serialize', 'directory' => 'metadata/metarefresh-ukaccess'), ), Remember that the `type` parameter here must match the `outputFormat` in the configuration of the module. Configuring the cron module --------------------------- Once we have configured metarefresh, we can edit the configuration file for the cron module: [root@simplesamlphp simplesamlphp]# vi config/module_cron.php The configuration should look similar to this: $config = array (        'key' => 'RANDOM_KEY',        'allowed_tags' => array('daily', 'hourly', 'frequent'),        'debug_message' => TRUE,        'sendemail' => TRUE, ); Bear in mind that the key is used as a security feature, to restrict access to your cron. Therefore, you need to make sure that the string here is a random key available to no one but you. Additionally, make sure that you include here the appropriate tags that you previously told metarefresh to use in the `cron` directive. Next, use your web browser to go to `https://YOUR_SERVER/simplesaml/module.php/cron/croninfo.php`. Make sure to properly set your server's address, as well as use HTTP or HTTPS accordingly, and also to specify the correct path to the root of your SimpleSAMLphp installation. Now, copy the cron configuration suggested: # Run cron [daily] 02 0 * * * curl --silent "https://YOUR_SERVER/simplesaml/module.php/cron/cron.php?key=RANDOM_KEY&tag=daily" > /dev/null 2>&1 # Run cron [hourly] 01 * * * * curl --silent "https://YOUR_SERVER/simplesaml/module.php/cron/cron.php?key=RANDOM_KEY&tag=hourly" > /dev/null 2>&1 Finally, add it to your crontab by going back to the terminal, and editing with: [root@simplesamlphp config]# crontab -e This will open up your favourite editor. If an editor different than the one you use normally appears, exit, and configure the `EDITOR` variable to tell the command line which editor it should use: [root@simplesamlphp config]# export EDITOR=emacs If you want to force the metadata to be refreshed manually, you can do so by going back to the cron page in the web interface. Then, just follow the appropriate links to execute the cron jobs you want. The page will take a while loading, and eventually show a blank page. It is so because the commands are intended to be run from cron, and therefore they produce no output. If this operation seems to run fine, navigate to the **SimpleSAMLphp Front page** › **Federation**. Here you will see a list of all the Identity Providers trusted. They will be listed with information about the maximum duration of their cached version, such as *(expires in 96.0 hours)*. Metadata duration ----------------- SAML metadata may supply a `cacheDuration` attribute which indicates the maximum time to keep metadata cached. Because this module is run from cron, it cannot decide how often it is run and enforce this duration on its own. Make sure to run metarefresh from cron at least as often as the shortest `cacheDuration` in your metadata sources. simplesamlphp-1.14.0/docs/simplesamlphp-install-repo.txt0000644000000000000000000000404612660345056022142 0ustar rootrootInstalling SimpleSAMLphp from the repository ============================================ These are some notes about running SimpleSAMLphp from the repository. Installing from github ---------------------- Go to the directory where you want to install SimpleSAMLphp: cd /var Then do a git clone: git clone git@github.com:simplesamlphp/simplesamlphp.git simplesamlphp Initialize configuration and metadata: cd /var/simplesamlphp cp -r config-templates/* config/ cp -r metadata-templates/* metadata/ Install the external dependencies with Composer (you can refer to [getcomposer.org](http://getcomposer.org/) to get detailed instructions on how to install Composer itself): php composer.phar install Upgrading --------- Go to the root directory of your SimpleSAMLphp installation: cd /var/simplesamlphp Ask git to update to the latest version: git fetch origin git pull origin master Install or upgrade the external dependencies with Composer ([get composer](http://getcomposer.org/)): php composer.phar install Migrating from Subversion ------------------------- If you installed SimpleSAMLphp from subversion, and want to keep updated on the development, you will have to migrate your installation to git. First, follow the steps to get a fresh install from github in a different directory. Skip the steps regarding configuration and metadata initialization, and copy all the files you might have modified instead (not only configuration and metadata, but also any custom modules or templates). Finally, proceed to install Composer and install all the dependencies with it. You may want to add all your custom files to the '.gitignore' file. If you really want to use subversion instead of git, or it is impossible for you to migrate (you cannot install git, for example), you might want to do a fresh install like the one described here, but using github's subversion interface. Refer to [github's documentation](https://help.github.com/articles/support-for-subversion-clients) for detailed instructions on how to do that. simplesamlphp-1.14.0/docs/simplesamlphp-upgrade-notes-1.7.txt0000644000000000000000000000153012660345056022604 0ustar rootrootUpgrade notes for SimpleSAMLphp 1.7 =================================== * The attribute names generated by the twitter and facebook authentication sources have changed. * Several new options have been added to config.php, and some have been renamed. The old options should still work, but it is suggested that you look at the config.php file in config-templates, and compare it to your own. * There have been several changes to the internal API. Most of the changes will not be noticed by the application using SimpleSAMLphp. See the changelog for more details about the changes. * Relative redirects are no longer supported. If your application passes relative URL's to the `SimpleSAML_Utilities::redirect()`-function, it will no longer work. This also applies if you pass relative URL's to other functions that do redirects. simplesamlphp-1.14.0/docs/simplesamlphp-idp-more.txt0000644000000000000000000001063412660345056021245 0ustar rootrootSimpleSAMLphp Identity Provider Advanced Topics =============================================== AJAX iFrame Single Log-Out -------------------------- If you have read about the AJAX iFrame Single Log-Out approach at Andreas' blog and want to enable it, edit your saml20-idp-hosted.php metadata, and add this configuration line for the IdP: 'logouttype' => 'iframe', Attribute Release Consent ------------------------- The attribute release consent is documented in a [separate document](./consent:consent). Support for bookmarking the login page -------------------------------------- Most SAML software crash fatally when users bookmark the login page and return later on when the cached session information is lost. This is natural as the login page happens in the middle of a SAML transaction, and the SAML software needs some references to the original request in order to be able to produce the SAML Response. SimpleSAMLphp has implemented a graceful fallback to tackle this situation. When SimpleSAMLphp is not able to lookup a session during the login process, it falls back to the *IdP-first flow*, described in the next section, where the reference to the request is not needed. What happens in the IdP-first flow is that a *SAML unsolicited response* is sent directly to the SP. An *unsolicited response* is a SAML Response with no reference to a SAML Request (no `InReplyTo` field). When a SimpleSAMLphp IdP falls back to IdP-first flow, the `RelayState` parameter sent by the SP in the SAML request is also lost. The RelayState information contain a reference key for the SP to lookup where to send the user after successfull authentication. The SimpleSAMLphp Service Provider supports configuring a static URL to redirect the user after a unsolicited response is received. See more information about the `RelayState` parameter in the next section: *IdP-first flow*. IdP-first flow -------------- If you do not want to start the SSO flow at the SP, you may use the IdP-first setup. To do this, redirect the user to the SSOService endpoint on the IdP with a `spentityid` parameter that matches the SP EntityID that the user should be authenticated for. Here is an example of such a URL: https://idp.example.org/simplesaml/saml2/idp/SSOService.php?spentityid=urn:mace:feide.no:someservice You can also add a RelayState parameter to the IdP-first URL: https://idp.example.org/simplesaml/saml2/idp/SSOService.php?spentityid=urn:mace:feide.no:someservice&RelayState=https://sp.example.org/somepage The RelayState parameter is often uset do carry the URL the SP should redirect to after authentication. ### IdP first with SAML 1.1 A SAML 1.1 SP does not send an authentication request to the IdP, but instead triggers IdP initiated authentication directly. If you want to do it manually, you can access the following URL: https://idp.example.org/simplesaml/shib13/idp/SSOService.php?providerId=urn:mace:feide.no:someservice&shire=https://sp.example.org/acs-endpoint&target=https://sp.example.org/somepage The parameters are as follows: `providerID` : The entityID of the SP. This parameter is required. `shire` : The AssertionConsumerService endpoint of the SP. This parameter is required. `target` : The target parameter the SP should receive with the authentication response. This is often the page the user should be sent to after authentication. This parameter is optional for the IdP, but must be specified if the SP you are targeting is running SimpleSAMLphp. : *Note*: This parameter must be sent as `target` (with lowercase letters) when starting the authentication, while it is sent as `TARGET` (with uppercase letters) in the authentication response. IdP-initiated logout -------------------- IdP-initiated logout can be initiated by visiting the URL: https://idp.example.org/simplesaml/saml2/idp/SingleLogoutService.php?ReturnTo= It will send a logout request to each SP, and afterwards return the user to the URL specified in the `ReturnTo` parameter. Bear in mind that IdPs might disallow redirecting to URLs other than those of their own for security reasons, so in order to get the redirection to work, it might be necessary to ask the IdP to whitelist the URL we are planning to redirect to. simplesamlphp-1.14.0/docs/simplesamlphp-upgrade-notes-1.5.txt0000644000000000000000000000235212660345056022605 0ustar rootrootUpgrade notes for SimpleSAMLphp 1.5 =================================== * `SimpleSAML_Session::isValid()` If your code calls `$session->isValid()` without an argument, you will now have to update it to pass an argument (probably `saml2`). The reason for this change is that calling `$session->isValid()` without an argument can easily create a security hole. * We have introduced a new module for SAML authentication. This authentication module supports both SAML 1.1 and SAML 2.0 IdPs. We have also added a new authentication framework which should replace the previous redirects to the initSSO-scripts. Relating to this change, we have also deprecated the `initSSO`-scripts for SAML 1.1 and SAML 2.0 authentication. The old methods will still be supported for a while, but new code should probably use the new code. See the [migration guide](simplesamlphp-sp-migration) for more information about this. * The `request.signing` option has been removed. That option was replaced with the `redirect.sign` and `redirect.validate` options, and has been depreceated for one year. * The `aggregator` module's configuration file has changed name. It was changed from `aggregator.php` to `module_aggregator.php`. simplesamlphp-1.14.0/docs/simplesamlphp-artifact-idp.txt0000644000000000000000000000717412660345056022105 0ustar rootrootAdding HTTP-Artifact support to the IdP ======================================= This document describes the necessary steps to enable support for the HTTP-Artifact binding on a SimpleSAMLphp IdP: 1. Configure SimpleSAMLphp to use memcache to store the session. 2. Enable support for sending artifacts in `saml20-idp-hosted`. 3. Add the webserver certificate to the generated metadata. Memcache -------- To enable memcache, you must first install and configure memcache on the server hosting your IdP. You need both a memcache server and a the PHP memcache client. How this is done depends on the distribution. If you are running Debian Lenny, you can install both by running: aptitude install memcached php5-memcache *Note*: For security, you must make sure that the memcache server is inaccessible to other hosts. The default configuration on Debian Lenny is for the memcache server to be accessible to only the local host. Once the memcache server is configured, you can configure simplesamlphp to use it to store sessions. You can do this by setting the `session.handler` option in `config.php` to `memcache`. If you are running memcache on a different server than the IdP, you must also change the `memcache_store.servers` option in `config.php`. Enabling artifact on the IdP ---------------------------- To enable the IdP to send artifacts, you must add the `saml20.sendartifact` option to the `saml20-idp-hosted` metadata file: $metadata['__DYNAMIC:1__'] = array( [....] 'auth' => 'example-userpass', 'saml20.sendartifact' => TRUE, ); Add new metadata to SPs ----------------------- After enabling the Artifact binding, your IdP metadata will change to add a ArtifactResolutionService endpoint. You therefore need to update the metadata for your IdP at your SPs. `saml20-idp-remote` metadata for SimpleSAMLphp SPs should contain something like: 'ArtifactResolutionService' => array( array( 'index' => 0, 'Location' => 'https://idp.example.org/simplesaml/saml2/idp/ArtifactResolutionService.php', 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:SOAP', ), ), SP metadata on the IdP ---------------------- An SP using the HTTP-Artifact binding must have an AssertionConsumerService endpoint supporting that binding. This means that you must use the complex endpoint format in `saml20-sp-remote` metadata. In general, that should look something like: 'AssertionConsumerService' => array ( array( 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST', 'Location' => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp', 'index' => 0, ), array( 'Binding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact', 'Location' => 'https://sp.example.org/simplesaml/module.php/saml/sp/saml2-acs.php/default-sp', 'index' => 2, ), ), (The specific values of the various fields will vary depending on the SP.) Certificate in metadata ----------------------- Some SPs validates the SSL certificate on the ArtifactResolutionService using the certificates in the metadata. You may therefore have to add the webserver certificate to the metadata that your IdP generates. To do this, you need to set the `https.certificate` option in the `saml20-idp-hosted` metadata file. That option should refer to a file containing the webserver certificate. $metadata['__DYNAMIC:1__'] = array( [....] 'auth' => 'example-userpass', 'saml20.sendartifact' => TRUE, 'https.certificate' => '/etc/apache2/webserver.crt', ); simplesamlphp-1.14.0/docs/simplesamlphp-maintenance.txt0000644000000000000000000002214512660345056022013 0ustar rootrootSimpleSAMLphp Maintenance ========================= SimpleSAMLphp news and documentation ------------------------------------ This document is part of the SimpleSAMLphp documentation suite. * [List of all SimpleSAMLphp documentation](http://simplesamlphp.org/docs) * [SimpleSAMLphp homepage](https://simplesamlphp.org) ## Session management SimpleSAMLphp has an abstraction layer for session management. That means it is possible to choose between different kind of session stores, as well as write new session store plugins. The `store.type` configuration option in `config.php` allows you to select which method SimpleSAMLphp should use to store the session information. Currently, three session handlers are included in the distribution: * `phpsession` uses the built in session management in PHP. This is the default, and is simplest to use. It will not work in a load-balanced environment in most configurations. * `memcache` uses the memcache software to cache sessions in memory. Sessions can be distributed and replicated among several memcache servers, enabling both load-balancing and fail-over. * `sql` stores the session in an SQL database. 'store.type' => 'phpsession', ### Configuring memcache To use the memcache session handler, set the `store.type` parameter in `config.php`: 'store.type' => 'memcache', memcache allows you to store multiple redundant copies of sessions on different memcache servers. The configuration parameter `memcache_store.servers` is an array of server groups. Every data item will be mirrored in every server group. Each server group is an array of servers. The data items will be load-balanced between all servers in each server group. Each server is an array of parameters for the server. The following options are available: `hostname` : Host name or ip address where the memcache server runs, or specify other transports like *unix:///path/ssp.sock* to use UNIX domain sockets. In that case, port will be ignored and forced to *0*. This is the only required option. `port` : Port number of the memcache server. If not set, the `memcache.default_port` ini setting is used. This is 11211 by default. The port will be forced to *0* when a UNIX domain socket is specified in *hostname*. `weight` : Weight of this server in this server group. [http://php.net/manual/en/function.Memcache-addServer.php](http://php.net/manual/en/function.Memcache-addServer.php) has more information about the weight option. `timeout` : Timeout for this server. By default, the timeout is 3 seconds. Here are two examples of configuration of memcache session handling: **Example 1. Example of redundant configuration with load balancing** Example of redundant configuration with load balancing: This configuration makes it possible to lose both servers in the a-group or both servers in the b-group without losing any sessions. Note that sessions will be lost if one server is lost from both the a-group and the b-group. 'memcache_store.servers' => array( array( array('hostname' => 'mc_a1'), array('hostname' => 'mc_a2'), ), array( array('hostname' => 'mc_b1'), array('hostname' => 'mc_b2'), ), ), **Example 2. Example of simple configuration with only one memcache server** Example of simple configuration with only one memcache server, running on the same computer as the web server: Note that all sessions will be lost if the memcache server crashes. 'memcache_store.servers' => array( array( array('hostname' => 'localhost'), ), ), The expiration value (`memcache_store.expires`) is the duration for which data should be retained in memcache. Data are dropped from the memcache servers when this time expires. The time will be reset every time the data is written to the memcache servers. This value should always be larger than the `session.duration` option. Not doing this may result in the session being deleted from the memcache servers while it is still in use. Set this value to 0 if you don't want data to expire. #### Note The oldest data will always be deleted if the memcache server runs out of storage space. **Example 3. Example of configuration setting for session expiration** Here is an example of this configuration parameter: 'memcache_store.expires' => 36 * (60*60), // 36 hours. #### Memcache PHP configuration Configure memcache to not do internal failover. This parameter is configured in `php.ini`. memcache.allow_failover = Off #### Environmental configuration Setup a firewall restricting access to the memcache server. Because SimpleSAMLphp uses a timestamp to check which session is most recent in a fail-over setup, it is very important to run synchronized clocks on all web servers where you run SimpleSAMLphp. ### Configuring SQL storage To store session to a SQL database, set the `store.type` option to `sql`. SimpleSAMLphp uses [PDO](http://www.php.net/manual/en/book.pdo.php) when accessing the database server, so the database source is configured as with a DSN. The DSN is stored in the `store.sql.dsn` option. See the [PDO driver manual](http://www.php.net/manual/en/pdo.drivers.php) for the DSN syntax used by the different databases. Username and password for accessing the database can be configured in the `store.sql.username` and `store.sql.password` options. The required tables are created automatically. If you are storing data from multiple separate SimpleSAMLphp installations in the same database, you can use the `store.sql.prefix` option to prevent conflicts. ## Logging and statistics SimpleSAMLphp supports standard `syslog` logging. As an alternative, you may log to flat files. ## Apache configuration ## PHP configuration Secure cookies (if you run HTTPS). Turn off PHPSESSID in query string. ## Getting ready for production Here are some checkpoints 1. Remove all entities in metadata files that you do not trust. It is easy to forget about some of the entities that were used for test. 2. If you during testing have been using a certificate that has been exposed (notably: the one found in the SimpleSAMLphp distribution): Obtain and install a new one. 3. Make sure you have installed the latest security upgrades for your OS. 4. Make sure to use HTTPS rather than HTTP. 5. Block access to your servers on anything except port 443. SimpleSAMLphp only uses plain HTTP(S), so there is no need to open ports for SOAP or other communication. ## Error handling, error reporting and metadata reporting SimpleSAMLphp supports allowing the user when encountering errors to send an e-mail to the administrator. You can turn off this feature in the config.php file. ## Multi-language support To add support for a new language, add your new language to the `language.available` configuration parameter in `config.php`: /* * Languages available and which language is default */ 'language.available' => array('en', 'no', 'da', 'es', 'xx'), 'language.default' => 'en', Please use the standardized two-character [language codes as specified in ISO-639-1](http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes). You also can set the default language. You should ensure that the default language is complete, as it is used as a fallback when a text is not available in the language selected by the user. Translation of SimpleSAMLphp is done through the SimpleSAMLphp translation portal. To translate SimpleSAMLphp to a new language, please contact the authors at the mailing list, and the new language may be added to the translation portal. * [Visit the SimpleSAMLphp translation portal](https://translation.rnd.feide.no/?aid=simplesamlphp) All strings that can be localized are found in the files `dictionaries/`. Add a new entry for each string, with your language code, like this: 'user_pass_header' => array( 'en' => 'Enter your username and password', 'no' => 'Skriv inn brukernavn og passord', 'xx' => 'Pooa jujjique jamba', ), You can translate as many of the texts as you would like; a full translation is not required unless you want to make this the default language. From the end users point of view, it looks best if all text fragments used in a given screen or form is in one single language. ## Customizing the web frontend with themes Documentation on theming is moved [to a separate document](simplesamlphp-theming). Support ------- If you need help to make this work, or want to discuss SimpleSAMLphp with other users of the software, you are fortunate: Around SimpleSAMLphp there is a great Open source community, and you are welcome to join! The forums are open for you to ask questions, contribute answers other further questions, request improvements or contribute with code or plugins of your own. - [SimpleSAMLphp homepage](https://simplesamlphp.org) - [List of all available SimpleSAMLphp documentation](http://simplesamlphp.org/docs/) - [Join the SimpleSAMLphp user's mailing list](https://simplesamlphp.org/lists) simplesamlphp-1.14.0/docs/simplesamlphp-nostate.txt0000644000000000000000000001431712660345056021210 0ustar rootrootDebugging "State Information Lost" errors ========================================= **"State Information Lost"** (`SimpleSAML_Error_NoState: NOSTATE`) This is one of the most common errors that you can encounter when configuring SimpleSAMLphp. Unfortunately, it is also a generic error that can have many possible causes. This document will attempt to describe what this error actually means, and some of the situations that can cause it. What is "state information"? ---------------------------- The "state information" is data that SimpleSAMLphp stores in association with a request. The request is typically a SAML 2.0 authentication request sent to the IdP, but it can also be other requests. This state information is given a random ID, e.g. "`_2da56e07840b59191d9797442b6b665d67d855cf77`", and is saved in the session of the user. What does it mean that it was lost? ----------------------------------- This means that we tried to load state information with a specified ID, but were unable to find it in the session of the user. What can cause it to be lost? ----------------------------- There are several ways that this can happen, but most of them have to do with session storage. Here we will outline some generic alternatives, and possible solutions. #### The domain name changed during authentication The domain name the IdP sends the response to is configured in the metadata of the IdP. This means that it may not match up with the domain name the user accessed. For example we may have the following scenario: 1. The user accesses `https://www.example.org/`. A session is created for the user, and the session cookie is set for the current domain (www.example.org). 1. The user needs to be authenticated. We therefore save some information about the current status in the state array, create a SAML 2.0 authentication request, and send it to the IdP. 1. The user logs in on the IdP. The IdP then sends a response to the SP at `example.org`. However, the metadata for the SP that is registered at the IdP uses `https://example.org/` (without `www`) as the domain the response should be sent to. The authentication response is therefore sent to that domain. 1. The SP (now at `https://example.org/`) tries to load the state information associated with the authentication response it received. But, because the domain name has changed, we do not receive the session cookie of the user. We are therefore unable to find the session of the user. When we attempt to load the state information from the session we are therefore unable to find it. There are several ways to solve this. One of the simplest is often to configure your webserver to only use one domain, and redirect all accesses to the other domain to the correct domain. A different solution is to change the session cookie settings, so that they are set for the "`example.org`" domain. If you are using PHP sessions, you should change this in `php.ini`. If not, you should change it with the '`session.cookie.domain`' option in `config/config.php`. In either case, it should be set to the top-level domain with a "dot" in front of it. E.g.: 'session.cookie.domain' => '.example.org', Or in php.ini: session.cookie_domain = ".example.org" Note that if you use PHP sessions, you will also have to make sure that your application uses the same domain when it sets the cookie. How that is done depends on your application. (See the section about mismatch between application PHP session settings and SimpleSAMLphp session settings.) #### Hopping between http and https If a cookie is set during a HTTPS session, it is not available when the same URL is later accessed over http. If your site is available over both http and https, check that you're using https consistently throughout the configuration. The best and most secure is to make your complete site available on https only, and redirect any http requests to https. #### Mismatch between PHP session settings for the application and SimpleSAMLphp If both the application you are trying to add SAML 2.0 support to and SimpleSAMLphp uses PHP session for session storage, and they don't agree on all the parameters, you can end up with this error. By default, SimpleSAMLphp uses the settings from `php.ini`, but these can be overridden in `config/config.php`. If this is the cause of your error, you have two choices: either change SimpleSAMLphp to use a different session storage method (e.g. memcache or sql), or change the session settings to match between the application and SimpleSAMLphp. In many cases it is simplest to adjust the session storage. If you decide to make the session settings match, you should change the settings in `php.ini`. This is to make sure that the settings apply to everything that uses the default settings. The following options in `php.ini` must match the settings used by the application: * `session.save_handler`: This is the method that is used to store the session. The default is "`files`". * `session.save_path`: This is the location the session files are saved. The default depends on your PHP installation. * `session.name`: This is the name of the session cookie. The default is "`PHPSESSID`". * `session.cookie_path`: The path that the session cookie is limited to. The default is "`/`", which means that it is available to all pages on your domain. * `session.cookie_domain`: This is the domain the session cookie is limited to. The default is unset, which makes the cookie available only to the current domain. What those settings should be set to depends on the application. The simplest way to determine it may be to look for calls to `session_set_cookie_params` in the application, and look at what parameters it uses. #### A generic problem saving sessions Sometimes the problem is caused by SimpleSAMLphp being unable to load and/or save sessions. This can be caused by the session settings being incorrect, or by a failure of some service required by the session storage. For example, if you are using memcache for session storage, you need to ensure that the memcache server is running and that the web server is able to connect to it. The same applies if you are saving the sessions to a SQL database. You may want to check your web server error log. If the PHP session handler fails, it may log an error message there. simplesamlphp-1.14.0/docs/simplesamlphp-customauth.txt0000644000000000000000000003311712660345056021726 0ustar rootrootImplementing custom username/password authentication ==================================================== This is a step-by-step guide for creating a custom username/password [authentication source](./simplesamlphp-authsource) for SimpleSAMLphp. An authentication source is responsible for authenticating the user, typically by getting a username and password, and looking it up in some sort of database. Create a custom module ---------------------- All custom code for SimpleSAMLphp should be contained in a [module](./simplesamlphp-modules). This ensures that you can upgrade your SimpleSAMLphp installation without overwriting your own code. In this example, we will call the module `mymodule`. It will be located under `modules/mymodule`. First we need to create the module directory: cd modules mkdir mymodule Since this is a custom module, it should always be enabled. Therefore we create a `default-enable` file in the module. We do that by copying the `default-enable` file from the `core` module. cd mymodule cp ../core/default-enable . Now that we have our own module, we can move on to creating an authentication source. Creating a basic authentication source -------------------------------------- Authentication sources are implemented using PHP classes. We are going to create an authentication source named `mymodule:MyAuth`. It will be implemented in the file `modules/mymodule/lib/Auth/Source/MyAuth.php`. To begin with, we will create a very simple authentication source, where the username and password is hardcoded into the source code. Create the file `modules/mymodule/lib/Auth/Source/MyAuth.php` with the following contents: array('theusername'), 'displayName' => array('Some Random User'), 'eduPersonAffiliation' => array('member', 'employee'), ); } } Some things to note: - The classname is `sspmod_mymodule_Auth_Source_MyAuth`. This tells SimpleSAMLphp to look for the class in `modules/mymodule/lib/Auth/Source/MyAuth.php`. - Our authentication source subclassese `sspmod_core_Auth_UserPassBase`. This is a helper-class that implements much of the common code needed for username/password authentication. - The `login` function receives the username and password the user enters. It is expected to authenticate the user. If the username or password is correct, it must return a set of attributes for the user. Otherwise, it must throw the `SimpleSAML_Error_Error('WRONGUSERPASS');` exception. - Attributes are returned as an associative array of `name => values` pairs. All attributes can have multiple values, so the values are always stored in an array. Configuring our authentication source ------------------------------------- Before we can test our authentication source, we must add an entry for it in `config/authsources.php`. `config/authsources.php` contains an list of enabled authentication sources. The entry looks like this: 'myauthinstance' => array( 'mymodule:MyAuth', ), You can add it to the beginning of the list, so that the file looks something like this: array( 'mymodule:MyAuth', ), /* Other authentication sources follow. */ ); `myauthinstance` is the name of this instance of the authentication source. (You are allowed to have multiple instances of an authentication source with different configuration.) The instance name is used to refer to this authentication source in other configuration files. The first element of the configuration of the authentication source must be `'mymodule:MyAuth'`. This tells SimpleSAMLphp to look for the `sspmod_mymodule_Auth_Source_MyAuth` class. Testing our authentication source --------------------------------- Now that we have configured the authentication source, we can test it by accessing "authentication"-page of the SimpleSAMLphp web interface. By default, the web interface can be found on `http://yourhostname.com/simplesaml/`. (Obviously, "yourhostname.com" should be replaced with your real hostname.) Then select the "Authentication"-tab, and choose "Test configured authentication sources". You should then receive a list of authentication sources from `config/authsources.php`. Select `myauthinstance`, and log in using "theusername" as the username, and "thepassword" as the password. You should then arrive on a page listing the attributes we return from the `login` function. Next, you should log out by following the log out link. Using our authentication source in an IdP ----------------------------------------- To use our new authentication source in an IdP we just need to update the IdP configuration to use it. Open `metadata/saml20-idp-hosted.php`. In that file you should locate the `auth`-option for your IdP, and change it to `myauthinstance`: 'myauthinstance', /* ... */ ); You can then test logging in to the IdP. If you have logged in previously, you may need to log out first. Adding configuration to our authentication source ------------------------------------------------- Instead of hardcoding options in our authentication source, they should be configurable. We are now going to extend our authentication source to allow us to configure the username and password in `config/authsources.php`. First, we need to define the properties in the class that should hold our configuration: private $username; private $password; Next, we create a constructor for the class. The constructor is responsible for parsing the configuration and storing it in the properties. public function __construct($info, $config) { parent::__construct($info, $config); if (!is_string($config['username'])) { throw new Exception('Missing or invalid username option in config.'); } $this->username = $config['username']; if (!is_string($config['password'])) { throw new Exception('Missing or invalid password option in config.'); } $this->password = $config['password']; } We can then use the properties in the `login` function. The complete class file should look like this: username = $config['username']; if (!is_string($config['password'])) { throw new Exception('Missing or invalid password option in config.'); } $this->password = $config['password']; } protected function login($username, $password) { if ($username !== $this->username || $password !== $this->password) { throw new SimpleSAML_Error_Error('WRONGUSERPASS'); } return array( 'uid' => array($this->username), 'displayName' => array('Some Random User'), 'eduPersonAffiliation' => array('member', 'employee'), ); } } We can then update our entry in `config/authsources.php` with the configuration options: 'myauthinstance' => array( 'mymodule:MyAuth', 'username' => 'theconfigusername', 'password' => 'theconfigpassword', ), Next, you should go to the "Test configured authentication sources" page again, and test logging in. Note that we have updated the username & password to "theconfigusername" and "theconfigpassword". (You may need to log out first before you can log in again.) A more complete example - custom database authentication -------------------------------------------------------- The [sqlauth:SQL](./sqlauth:sql) authentication source can do simple authentication against SQL databases. However, in some cases it cannot be used, for example because the database layout is too complex, or because the password validation routines cannot be implemented in SQL. What follows is an example of an authentication source that fetches an user from a database, and validates the password using a custom function. This code assumes that the database contains a table that looks like this: CREATE TABLE userdb ( username VARCHAR(32) PRIMARY KEY NOT NULL, password_hash VARCHAR(64) NOT NULL, full_name TEXT NOT NULL); An example user (with password "secret"): INSERT INTO userdb (username, password_hash, full_name) VALUES('exampleuser', 'QwVYkvlrAMsXIgULyQ/pDDwDI3dF2aJD4XeVxg==', 'Example User'); In this example, the `password_hash` contains a base64 encoded SSHA password. A SSHA password is created like this: $password = 'secret'; $numSalt = 8; /* Number of bytes with salt. */ $salt = ''; for ($i = 0; $i < $numSalt; $i++) { $salt .= chr(mt_rand(0, 255)); } $digest = sha1($password . $salt, TRUE); $password_hash = base64_encode($digest . $salt); The class follows: dsn = $config['dsn']; if (!is_string($config['username'])) { throw new Exception('Missing or invalid username option in config.'); } $this->username = $config['username']; if (!is_string($config['password'])) { throw new Exception('Missing or invalid password option in config.'); } $this->password = $config['password']; } /** * A helper function for validating a password hash. * * In this example we check a SSHA-password, where the database * contains a base64 encoded byte string, where the first 20 bytes * from the byte string is the SHA1 sum, and the remaining bytes is * the salt. */ private function checkPassword($passwordHash, $password) { $passwordHash = base64_decode($passwordHash); $digest = substr($passwordHash, 0, 20); $salt = substr($passwordHash, 20); $checkDigest = sha1($password . $salt, TRUE); return $digest === $checkDigest; } protected function login($username, $password) { /* Connect to the database. */ $db = new PDO($this->dsn, $this->username, $this->password); $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); /* Ensure that we are operating with UTF-8 encoding. * This command is for MySQL. Other databases may need different commands. */ $db->exec("SET NAMES 'utf8'"); /* With PDO we use prepared statements. This saves us from having to escape * the username in the database query. */ $st = $db->prepare('SELECT username, password_hash, full_name FROM userdb WHERE username=:username'); if (!$st->execute(array('username' => $username))) { throw new Exception('Failed to query database for user.'); } /* Retrieve the row from the database. */ $row = $st->fetch(PDO::FETCH_ASSOC); if (!$row) { /* User not found. */ SimpleSAML_Logger::warning('MyAuth: Could not find user ' . var_export($username, TRUE) . '.'); throw new SimpleSAML_Error_Error('WRONGUSERPASS'); } /* Check the password. */ if (!$this->checkPassword($row['password_hash'], $password)) { /* Invalid password. */ SimpleSAML_Logger::warning('MyAuth: Wrong password for user ' . var_export($username, TRUE) . '.'); throw new SimpleSAML_Error_Error('WRONGUSERPASS'); } /* Create the attribute array of the user. */ $attributes = array( 'uid' => array($username), 'displayName' => array($row['full_name']), 'eduPersonAffiliation' => array('member', 'employee'), ); /* Return the attributes. */ return $attributes; } } And configured in `config/authsources.php`: 'myauthinstance' => array( 'mymodule:MyAuth', 'dsn' => 'mysql:host=sql.example.org;dbname=userdatabase', 'username' => 'db_username', 'password' => 'secret_db_password', ), simplesamlphp-1.14.0/docs/simplesamlphp-artifact-sp.txt0000644000000000000000000000257712660345056021755 0ustar rootrootUsing HTTP-Artifact from a SimpleSAMLphp SP =========================================== This document describes how to use the HTTP-Artifact binding to receive authentication responses from the IdP. Which binding the IdP should use when sending authentication responses is controlled by the `ProtocolBinding` in the SP configuration. To make your Service Provider (SP) request that the response from the IdP is sent using the HTTP-Artifact binding, this option must be set to the HTTP-Artifact binding. In addition to selecting the binding, you must also add a private key and certificate to your SP. This is used for SSL client authentication when contacting the IdP. To generate a private key and certificate, you may use the `openssl` commandline utility: openssl req -newkey rsa:2048 -new -x509 -days 3652 -nodes -out sp.example.org.crt -keyout sp.example.org.pem You can then add the private key and certificate to the SP configuration. When this is done, you can add the metadata of your SP to the IdP, and test the authentication. Example configuration --------------------- 'artifact-sp' => array( 'saml:SP', 'ProtocolBinding' => 'urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact', 'privatekey' => 'sp.example.org.pem', 'certificate' => 'sp.example.org.crt', ), See the [SP configuration reference](./saml:sp) for a description of the options. simplesamlphp-1.14.0/docs/simplesamlphp-sp-api.txt0000644000000000000000000001611012660345056020715 0ustar rootrootSimpleSAMLphp SP API reference ============================== This document describes the SimpleSAML_Auth_Simple API. This is the preferred API for integrating SimpleSAMLphp with other applications. Constructor ----------- new SimpleSAML_Auth_Simple(string $authSource) The constructor initializes a SimpleSAML_Auth_Simple object. ### Parameters It has a single parameter, which is the ID of the authentication source that should be used. This authentication source must exist in `config/authsources.php`. ### Example $auth = new SimpleSAML_Auth_Simple('default-sp'); `isAuthenticated` ----------------- bool isAuthenticated() Check whether the user is authenticated with this authentication source. `TRUE` is returned if the user is authenticated, `FALSE` if not. ### Example if (!$auth->isAuthenticated()) { /* Show login link. */ print('Login'); } `requireAuth` ------------- void requireAuth(array $params = array()) Make sure that the user is authenticated. This function will only return if the user is authenticated. If the user isn't authenticated, this function will start the authentication process. ### Parameters `$params` is an associative array with named parameters for this function. See the documentation for the `login`-function for a description of the parameters. ### Example 1 $auth->requireAuth(); print("Hello, authenticated user!"); ### Example 2 /* * Return the user to the frontpage after authentication, don't post * the current POST data. */ $auth->requireAuth(array( 'ReturnTo' => 'https://sp.example.org/', 'KeepPost' => FALSE, )); print("Hello, authenticated user!"); `login` ------------- void login(array $params = array()) Start a login operation. This function will always start a new authentication process. ### Parameters The following global parameters are supported: `ErrorURL` (`string`) : A URL to a page which will receive errors that may occur during authentication. `KeepPost` (`bool`) : If set to `TRUE`, the current POST data will be submitted again after authentication. The default is `TRUE`. `ReturnTo` (`string`) : The URL the user should be returned to after authentication. The default is to return the user to the current page. `ReturnCallback` (`array`) : The function we should call when the user finishes authentication. The [`saml:SP`](./saml:sp) authentication source also defines some parameters. ### Example # Send a passive authentication request. $auth->login(array( 'isPassive' => TRUE, 'ErrorURL' => 'https://.../error_handler.php', )); `logout` -------- void logout(mixed $params = NULL) Log the user out. After logging out, the user will either be redirected to another page, or a function will be called. This function never returns. ### Parameters `$params` : Parameters for the logout operation. This can either be a simple string, in which case it is interpreted as the URL the user should be redirected to after logout, or an associative array with logout parameters. If this parameter isn't specified, we will redirect the user to the current URL after logout. If the parameter is an an array, it can have the following options: - `ReturnTo`: The URL the user should be returned to after logout. - `ReturnCallback`: The function that should be called after logout. - `ReturnStateParam`: The parameter we should return the state in when redirecting. - `ReturnStateStage`: The stage the state array should be saved with. The `ReturnState` parameters allow access to the result of the logout operation after it completes. ### Example 1 Logout, and redirect to the specified URL. $auth->logout('https://sp.example.org/logged_out.php'); ### Example 2 Same as the previous, but check the result of the logout operation afterwards. $auth->logout(array( 'ReturnTo' => 'https://sp.example.org/logged_out.php', 'ReturnStateParam' => 'LogoutState', 'ReturnStateStage' => 'MyLogoutState', )); And in logged_out.php: $state = SimpleSAML_Auth_State::loadState((string)$_REQUEST['LogoutState'], 'MyLogoutState'); $ls = $state['saml:sp:LogoutStatus']; /* Only works for SAML SP */ if ($ls['Code'] === 'urn:oasis:names:tc:SAML:2.0:status:Success' && !isset($ls['SubCode'])) { /* Successful logout. */ echo("You have been logged out."); } else { /* Logout failed. Tell the user to close the browser. */ echo("We were unable to log you out of all your sessions. To be completely sure that you are logged out, you need to close your web browser."); } `getAttributes` --------------- array getAttributes() Retrieve the attributes of the current user. If the user isn't authenticated, an empty array will be returned. The attributes will be returned as an associative array with the name of the attribute as the key and the value as an array of one or more strings: array( 'uid' => array('testuser'), 'eduPersonAffiliation' => array('student', 'member'), ) ### Example $attrs = $auth->getAttributes(); if (!isset($attrs['displayName'][0])) { throw new Exception('displayName attribute missing.'); } $name = $attrs['displayName'][0]; print('Hello, ' . htmlspecialchars($name)); `getAuthData` --------------- mixed getAuthData(string $name) Retrieve the specified authentication data for the current session. NULL is returned if the user isn't authenticated. The available authentication data depends on the module used for authentication. See the [`saml:SP`](./saml:sp) reference for information about available SAML authentication data. ### Example $idp = $auth->getAuthData('saml:sp:IdP'); print('You are logged in from: ' . htmlspecialchars($idp)); `getLoginURL` ------------- string getLoginURL(string $returnTo = NULL) Retrieve a URL that can be used to start authentication. ### Parameters `$returnTo` : The URL the user should be returned to after authentication. The default is the current page. ### Example $url = $auth->getLoginURL(); print('Login'); ### Note The URL returned by this function is static, and will not change. You can easily create your own links without using this function. The URL should be: .../simplesaml/module.php/core/as_login.php?AuthId=&ReturnTo= `getLogoutURL` -------------- string getLogoutURL(string $returnTo = NULL) Retrieve a URL that can be used to trigger logout. ### Parameters `$returnTo` : The URL the user should be returned to after logout. The default is the current page. ### Example $url = $auth->getLogoutURL(); print('Logout'); ### Note The URL returned by this function is static, and will not change. You can easily create your own links without using this function. The URL should be: .../simplesaml/module.php/core/as_logout.php?AuthId=&ReturnTo= simplesamlphp-1.14.0/docs/simplesamlphp-sp-migration.txt0000644000000000000000000002300712660345056022140 0ustar rootrootMigrating to the `saml` module ============================== This document describes how you can migrate your code to use the `saml` module for authentication against SAML 2.0 and SAML 1.1 IdPs. It assumes that you have previously set up a SP by using redirects to `saml2/sp/initSSO.php`. The steps we are going to follow are: 1. Create a new authentication source. 2. Add the metadata for this authentication source to the IdP. 3. Test the new authentication source. 4. Convert the application to use the new API. 5. Test the application. 6. Remove the old metadata from the IdP. 7. Disable the old SAML 2 SP. Create a new authentication source ---------------------------------- In this step we are going to create an authentication source which uses the `saml` module for authentication. To do this, we open `config/authsources.php`. Create the file if it does not exist. If you create the file, it should looke like this: array( 'saml:SP', /* * The entity ID of this SP. * Can be NULL/unset, in which case an entity ID is generated based on the metadata URL. */ 'entityID' => NULL, /* * The entity ID of the IdP this should SP should contact. * Can be NULL/unset, in which case the user will be shown a list of available IdPs. */ 'idp' => NULL, /* Here you can add other options to the SP. */ ), `default-sp` is the name of the authentication source. It is used to refer to this authentication source when we use it. `saml:SP` tells SimpleSAMLphp that authentication with this authentication source is handled by the `saml` module. The `idp` option should be set to the same value that is set in `default-saml20-idp` in `config.php`. To ease migration, you probably want the entity ID on the new SP to be different than on the old SP. This makes it possible to have both the old and the new SP active on the IdP at the same time. You can also add other options this authentication source. See the [`saml:SP`](./saml:sp) documentation for more information. Add the metadata for this authentication source to the IdP ---------------------------------------------------------- After adding the authentication source on the SP, you need to register the metadata on the IdP. To retrieve the metadata, open the frontpage of your SimpleSAMLphp installation, and go to the federation tab. You should have a list of metadata entries, and one will be marked with the name of the new authentication source. In our case, that was `default-sp`. Click the `Show metadata` link, and you will arrive on a web page with the metadata for that service provider. How you proceed from here depends on which IdP you are connecting to. If you use a SimpleSAMLphp IdP, you can use the metadata in the flat file format at the bottom of the page. That metadata should be added to `saml20-sp-remote.php` on the IdP. For other IdPs you probably want to use the XML metadata. Test the new authentication source ---------------------------------- You should now be able to log in using the new authentication source. Go to the frontpage of your SimpleSAMLphp installation and open the authentication tab. There you will find a link to test authentication sources. Click that link, and select the name of your authentication source (`default-sp` in our case). You should be able to log in using that authentication source, and receive the attributes from the IdP. Convert the application to use the new API ------------------------------------------ This section will go through some common changes that you need to do when you are using SimpleSAMLphp from a different application. ### `_include.php` You should also no longer include `.../simplesamlphp/www/_include.php`. Instead, you should include `.../simplesamlphp/lib/_autoload.php`. This means that you replace lines like: require_once('.../simplesamlphp/www/_include.php'); with: require_once('.../simplesamlphp/lib/_autoload.php'); `_autoload.php` will register an autoloader function for the SimpleSAMLphp classes. This makes it possible to access the classes from your application. `_include.php` does the same, but also has some side-effects that you may not want in your application. If you load any SimpleSAMLphp class files directly, you should remove those lines. That means that you should remove lines like the following: require_once('SimpleSAML/Utilities.php'); require_once('SimpleSAML/Session.php'); require_once('SimpleSAML/XHTML/Template.php'); ### Authentication API There is a new authentication API in SimpleSAMLphp which can be used to authenticate against authentication sources. This API is designed to handle the common operations. #### Overview This is a quick overview of the API: /* Get a reference to our authentication source. */ $as = new SimpleSAML_Auth_Simple('default-sp'); /* Require the user to be authentcated. */ $as->requireAuth(); /* When that function returns, we have an authenticated user. */ /* * Retrieve attributes of the user. * * Note: If the user isn't authenticated when getAttributes() is * called, an empty array will be returned. */ $attributes = $as->getAttributes(); /* Log the user out. */ $as->logout(); #### `$config` and `$session` Generally, if you have: $config = SimpleSAML_Configuration::getInstance(); $session = SimpleSAML_Session::getSessionFromRequest(); you should replace it with this single line: $as = new SimpleSAML_Auth_Simple('default-sp'); #### Requiring authentication Blocks of code like the following: /* Check if valid local session exists.. */ if (!isset($session) || !$session->isValid('saml2') ) { SimpleSAML_Utilities::redirect( '/' . $config->getBaseURL() . 'saml2/sp/initSSO.php', array('RelayState' => SimpleSAML_Utilities::selfURL()) ); } should be replaced with a single call to `requireAuth()`: $as->requireAuth(); #### Fetching attributes Where you previously called: $session->getAttributes(); you should now call: $as->getAttributes(); #### Logging out Redirecting to the initSLO-script: SimpleSAML_Utilities::redirect( '/' . $config->getBaseURL() . 'saml2/sp/initSLO.php', array('RelayState' => SimpleSAML_Utilities::selfURL()) ); should be replaced with a call to `logout()`: $as->logout(); If you want to return to a specific URL after logging out, you should include that URL as a parameter to the logout function: $as->logout('https://example.org/'); Please make sure the URL is trusted. If you obtain the URL from the user input, make sure it is trusted before calling $as->logout(), by using the SimpleSAML_Utilities::checkURLAllowed() method. #### Login link If you have any links to the initSSO-script, those links must be replaced with links to a new script. The URL to the new script is `https://.../simplesaml/module.php/core/as_login.php`. It has two mandatory parameters: * `AuthId`: The id of the authentication source. * `ReturnTo`: The URL the user should be redirected to after authentication. #### Logout link Any links to the initSLO-script must be replaced with links to a new script. The URL to the new script is `https://.../simplesaml/module.php/core/as_logout.php`. It has two mandatory parameters: * `AuthId`: The id of the authentication source. * `ReturnTo`: The URL the user should be redirected to after logout. Test the application -------------------- How you test the application is highly dependent on the application, but here are the elements you should test: ### SP initiated login Make sure that it is still possible to log into the application. ### IdP initiated login If you use a SimpleSAMLphp IdP, and you want users to be able to bookmark the login page, you need to test IdP initiated login. To test IdP initiated login from a SimpleSAMLphp IdP, you can access: https://.../simplesaml/saml2/idp/SSOService.php?spentityid=&RelayState= Note that the RelayState parameter is only supported if the IdP runs version 1.5 of SimpleSAMLphp. If it isn't supported by the IdP, you need to configure the `RelayState` option in the authentication source configuration. ### SP initiated logout Make sure that logging out of your application also logs out of the IdP. If this does not work, users who log out of your application can log in again without entering any username or password. ### IdP initiated logout This is used by the IdP if the user logs out of a different SP connected to the IdP. In this case, the user should also be logged out of your application. The easiest way to test this is if you have two SPs connected to the IdP. You can then log out of one SP and check that you are also logged out of the other. Remove the old metadata from the IdP ------------------------------------ Once the new SP works correctly, you can remove the metadata for the old SP from the IdP. How you do that depends on the IdP. If you are running a SimpleSAMLphp IdP, you can remove the entry for the old SP in `metadata/saml20-sp-remote.php`. Disable the old SAML 2 SP ------------------------- You may also want to disable the old SP code in SimpleSAMLphp. To do that, open `config/config.php`, and change the `enable.saml20-sp` option to `FALSE`. simplesamlphp-1.14.0/docs/simplesamlphp-reference-sp-remote.txt0000644000000000000000000004030112660345056023372 0ustar rootrootSP remote metadata reference ============================ This is a reference for metadata options available for `metadata/saml20-sp-remote.php` and `metadata/shib13-sp-remote.php`. Both files have the following format: array( 'en' => 'A service', 'no' => 'En tjeneste', ), `OrganizationName` : The name of the organization responsible for this SPP. This name does not need to be suitable for display to end users. : This option can be translated into multiple languages by specifying the value as an array of language-code to translated name: 'OrganizationName' => array( 'en' => 'Example organization', 'no' => 'Eksempel organisation', ), : *Note*: If you specify this option, you must also specify the `OrganizationURL` option. `OrganizationDisplayName` : The name of the organization responsible for this IdP. This name must be suitable for display to end users. If this option isn't specified, `OrganizationName` will be used instead. : This option can be translated into multiple languages by specifying the value as an array of language-code to translated name. : *Note*: If you specify this option, you must also specify the `OrganizationName` option. `OrganizationURL` : A URL the end user can access for more information about the organization. : This option can be translated into multiple languages by specifying the value as an array of language-code to translated URL. : *Note*: If you specify this option, you must also specify the `OrganizationName` option. `privacypolicy` : This is an absolute URL for where an user can find a privacypolicy for this SP. If set, this will be shown on the consent page. `%SPENTITYID%` in the URL will be replaced with the entity id of this service provider. : Note that this option also exists in the IdP-hosted metadata. This entry in the SP-remote metadata overrides the option in the IdP-hosted metadata. `userid.attribute` : The attribute name of an attribute which uniquely identifies the user. This attribute is used if SimpleSAMLphp needs to generate a persistent unique identifier for the user. This option can be set in both the IdP-hosted and the SP-remote metadata. The value in the sp-remote metadata has the highest priority. The default value is `eduPersonPrincipalName`. : Note that this option also exists in the IdP-hosted metadata. This entry in the SP-remote metadata overrides the option in the IdP-hosted metadata. SAML 2.0 options ---------------- The following SAML 2.0 options are available: `AssertionConsumerService` : The URL of the AssertionConsumerService endpoint for this SP. This option is required - without it you will not be able to send responses back to the SP. : The value of this option is specified in one of several [endpoint formats](./simplesamlphp-metadata-endpoints). `attributes.NameFormat` : What value will be set in the Format field of attribute statements. This parameter can be configured multiple places, and the actual value used is fetched from metadata by the following priority: : 1. SP Remote Metadata 2. IdP Hosted Metadata : The default value is: `urn:oasis:names:tc:SAML:2.0:attrname-format:basic` : Some examples of values specified in the SAML 2.0 Core Specification: : - `urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified` - `urn:oasis:names:tc:SAML:2.0:attrname-format:uri` (The default in Shibboleth 2.0) - `urn:oasis:names:tc:SAML:2.0:attrname-format:basic` (The default in Sun Access Manager) : You can also define your own value. : Note that this option also exists in the IdP-hosted metadata. This entry in the SP-remote metadata overrides the option in the IdP-hosted metadata. : (This option was previously named `AttributeNameFormat`.) `encryption.blacklisted-algorithms` : Blacklisted encryption algorithms. This is an array containing the algorithm identifiers. : Note that this option also exists in the IdP-hosted metadata. This entry in the SP-remote metadata overrides the option in the [IdP-hosted metadata](./simplesamlphp-reference-idp-hosted). : The RSA encryption algorithm with PKCS#1 v1.5 padding is blacklisted by default for security reasons. Any assertions encrypted with this algorithm will therefore fail to decrypt. You can override this limitation by defining an empty array in this option (or blacklisting any other algorithms not including that one). However, it is strongly discouraged to do so. For your own safety, please include the string 'http://www.w3.org/2001/04/xmlenc#rsa-1_5' if you make use of this option. `ForceAuthn` : Set this `TRUE` to force the user to reauthenticate when the IdP receives authentication requests from this SP. The default is `FALSE`. `NameIDFormat` : The `NameIDFormat` this SP should receive. The three most commonly used values are: : 1. `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` 2. `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent` 3. `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress` : The `transient` format will generate a new unique ID every time the SP logs in. : To properly support the `persistent` and `emailAddress` formats, you should configure [NameID generation filters](./saml:nameid) on your IdP. `nameid.encryption` : Whether NameIDs sent to this SP should be encrypted. The default value is `FALSE`. : Note that this option also exists in the IdP-hosted metadata. This entry in the SP-remote metadata overrides the option in the [IdP-hosted metadata](./simplesamlphp-reference-idp-hosted). `SingleLogoutService` : The URL of the SingleLogoutService endpoint for this SP. This option is required if you want to implement single logout for this SP. If the option isn't specified, this SP will not be logged out automatically when a single logout operation is initialized. : The value of this option is specified in one of several [endpoint formats](./simplesamlphp-metadata-endpoints). `SingleLogoutServiceResponse` : The URL logout responses to this SP should be sent. If this option is unspecified, the `SingleLogoutService` endpoint will be used as the recipient of logout responses. `SPNameQualifier` : SP NameQualifier for this SP. If not set, the IdP will set the SPNameQualifier to be the SP entity ID. `certData` : The base64 encoded certificate for this SP. This is an alternative to storing the certificate in a file on disk and specifying the filename in the `certificate`-option. `certificate` : Name of certificate file for this SP. The certificate is used to verify the signature of messages received from the SP (if `redirect.validate`is set to `TRUE`), and to encrypting assertions (if `assertion.encryption` is set to TRUE and `sharedkey` is unset.) `saml20.sign.response` : Whether `` messages should be signed. Defaults to `TRUE`. : Note that this option also exists in the IdP-hosted metadata. The value in the SP-remote metadata overrides the value in the IdP-hosted metadata. `saml20.sign.assertion` : Whether `` elements should be signed. Defaults to `TRUE`. : Note that this option also exists in the IdP-hosted metadata. The value in the SP-remote metadata overrides the value in the IdP-hosted metadata. `signature.algorithm` : The algorithm to use when signing any message sent to this specific service provider. Defaults to RSA-SHA1. : Note that this option also exists in the IdP-hosted metadata. The value in the SP-remote metadata overrides the value in the IdP-hosted metadata. : Possible values: * `http://www.w3.org/2000/09/xmldsig#rsa-sha1` *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future. * `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` `signature.privatekey` : Name of private key file for this IdP, in PEM format. The filename is relative to the cert/-directory. : Note that this option also exists in the IdP-hosted metadata. This entry in the SP-remote metadata overrides the option `privatekey` in the IdP-hosted metadata. `signature.privatekey_pass` : Passphrase for the private key. Leave this option out if the private key is unencrypted. : Note that this option only is used if `signature.privatekey` is present. `signature.certificate` : Certificate file included by IdP for KeyInfo within the signature for the SP, in PEM format. The filename is relative to the cert/-directory. : If `signature.privatekey` is present and `signature.certificate` is left blank, X509Certificate will not be included with the signature. `simplesaml.nameidattribute` : When the value of the `NameIDFormat`-option is set to either `email` or `persistent`, this is the name of the attribute which should be used as the value of the `NameID`. The attribute must be in the set of attributes exported to the SP (that is, be in the `attributes` array). For more advanced control over `NameID`, including the ability to specify any attribute regardless of the set sent to the SP, see the [NameID processing filters](./saml:nameid). : Typical values can be `mail` for when using the `email` format, and `eduPersonTargetedID` when using the `persistent` format. `simplesaml.attributes` : Whether the SP should receive any attributes from the IdP. The default value is `TRUE`. `attributeencodings` : What encoding should be used for the different attributes. This is an array which maps attribute names to attribute encodings. There are three different encodings: : - `string`: Will include the attribute as a normal string. This is the default. : - `base64`: Store the attribute as a base64 encoded string. This is the default when the `base64attributes`-option is set to `TRUE`. : - `raw`: Store the attribute without any modifications. This makes it possible to include raw XML in the response. `sign.logout` : Whether to sign logout messages sent to this SP. : Note that this option also exists in the IdP-hosted metadata. The value in the SP-remote metadata overrides the value in the IdP-hosted metadata. `validate.authnrequest` : Whether we require signatures on authentication requests sent from this SP. : Note that this option also exists in the IdP-hosted metadata. The value in the SP-remote metadata overrides the value in the IdP-hosted metadata. `validate.logout` : Whether we require signatures on logout messages sent from this SP. : Note that this option also exists in the IdP-hosted metadata. The value in the SP-remote metadata overrides the value in the IdP-hosted metadata. ### Encrypting assertions It is possible to encrypt the assertions sent to a SP. Currently the only algorithm supported is `AES128_CBC` or `RIJNDAEL_128`. There are two modes of encryption supported by SimpleSAMLphp. One is symmetric encryption, in which case both the SP and the IdP needs to share a key. The other mode is the use of public key encryption. In that mode, the public key of the SP is extracted from the certificate of the SP. `assertion.encryption` : Whether assertions sent to this SP should be encrypted. The default value is `FALSE`. : Note that this option also exists in the IdP-hosted metadata. This entry in the SP-remote metadata overrides the option in the IdP-hosted metadata. `sharedkey` : Symmetric key which should be used for encryption. This should be a 128-bit key. If this option is not specified, public key encryption will be used instead. ### Fields for signing and validating messages SimpleSAMLphp only signs authentication responses by default. Signing of logout requests and logout responses can be enabled by setting the `redirect.sign` option. Validation of received messages can be enabled by the `redirect.validate` option. These options overrides the options set in `saml20-idp-hosted`. `redirect.sign` : Whether logout requests and logout responses sent to this SP should be signed. The default is `FALSE`. `redirect.validate` : Whether authentication requests, logout requests and logout responses received from this SP should be validated. The default is `FALSE` **Example: Configuration for validating messages** 'redirect.validate' => TRUE, 'certificate' => 'example.org.crt', ### Fields for scoping Only relevant if you are a proxy/bridge and wants to limit the idps this sp can use. `IDPList` : The list of scoped idps ie. the list of entityids for idps that are relevant for this sp. The final list is the concatenation of the list given as parameter to InitSSO (at the sp), the list configured at the sp and the list configured at the ipd (here) for this sp. The intersection of the final list and the idps configured at the at this idp will be presented to the user at the discovery service if neccessary. If only one idp is in the intersection the discoveryservice will go directly to the idp. **Example: Configuration for scoping** 'IDPList' => array('https://idp1.wayf.dk', 'https://idp2.wayf.dk'), Shibboleth 1.3 options ---------------------- The following options for Shibboleth 1.3 SP's are avaiblable: `AssertionConsumerService` : The URL of the AssertionConsumerService endpoint for this SP. This endpoint must accept the SAML responses encoded with the `urn:oasis:names:tc:SAML:1.0:profiles:browser-post` encoding. This option is required - without it you will not be able to send responses back to the SP. : The value of this option is specified in one of several [endpoint formats](./simplesamlphp-metadata-endpoints). `NameQualifier` : What the value of the `NameQualifier`-attribute of the ``-element should be. The default value is the entity ID of the SP. `audience` : The value which should be given in the ``-element in the ``-element in the response. The default value is the entity ID of the SP. `scopedattributes` : Array with names of attributes which should be scoped. Scoped attributes will receive a `Scope`-attribute on the `AttributeValue`-element. The value of the Scope-attribute will be taken from the attribute value: : `someuser@example.org` : will be transformed into : `someuser` : By default, no attributes are scoped. This option overrides the option with the same name in the `shib13-idp-hosted.php` metadata file. simplesamlphp-1.14.0/docs/simplesamlphp-metadata-extensions-ui.txt0000644000000000000000000002552412660345056024125 0ustar rootrootSAML V2.0 Metadata Extensions for Login and Discovery User Interface ============================= * Author: Timothy Ace [tace@synacor.com](mailto:tace@synacor.com) This is a reference for the SimpleSAMLphp implementation of the [SAML V2.0 Metadata Extensions for Login and Discovery User Interface](http://docs.oasis-open.org/security/saml/Post2.0/sstc-saml-metadata-ui/v1.0/sstc-saml-metadata-ui-v1.0.pdf) defined by OASIS. The metadata extensions are available to both IdP and SP usage of SimpleSAMLphp. For an IdP, the entries are placed in `metadata/saml20-idp-hosted.php`, for an SP, they are put inside the relevant entry in `authsources.php`. An example for an IdP: array( 'DisplayName' => array( 'en' => 'English name', 'es' => 'Nombre en Español', ), 'Description' => array( 'en' => 'English description', 'es' => 'Descripción en Español', ), 'InformationURL' => array( 'en' => 'http://example.com/info/en', 'es' => 'http://example.com/info/es', ), 'PrivacyStatementURL' => array( 'en' => 'http://example.com/privacy/en', 'es' => 'http://example.com/privacy/es', ), 'Keywords' => array( 'en' => array('communication', 'federated session'), 'es' => array('comunicación', 'sesión federated'), ), 'Logo' => array( array( 'url' => 'http://example.com/logo1.png', 'height' => 200, 'width' => 400, 'lang' => 'en', ), array( 'url' => 'http://example.com/logo2.png', 'height' => 201, 'width' => 401, ), ), ), 'DiscoHints' => array( 'IPHint' => array('130.59.0.0/16', '2001:620::0/96'), 'DomainHint' => array('example.com', 'www.example.com'), 'GeolocationHint' => array('geo:47.37328,8.531126', 'geo:19.34343,12.342514'), ), /* ... */ ); And for an SP it could look like this: array( 'saml:SP', 'UIInfo' => array( 'DisplayName' => array( 'en' => 'English name', 'es' => 'Nombre en Español' ), 'Description' => array( 'en' => 'English description', 'es' => 'Descripción en Español ), ), /* ... */ ), ); The OASIS specification primarily defines how an entity can communicate metadata related to IdP or service discovery and identification. There are two different types of extensions defined. There are the ``elements that define how an IdP or SP should be displayed and there are the `` elements that define when an IdP should be chosen/displayed. UIInfo Items -------------- These elements are used for IdP and SP discovery to determine what to display about an IdP or SP. These properties are all children of the `UIInfo` key. *Note*: Most elements are localized strings that specify the language using the array key as the language-code: 'DisplayName' => array( 'en' => 'English name', 'es' => 'Nombre en Español', ), `DisplayName` : The localized list of names for this entity 'DisplayName' => array( 'en' => 'English name', 'es' => 'Nombre en Español', ), `Description` : The localized list of statements used to describe this entity 'Description' => array( 'en' => 'English description', 'es' => 'Descripción en Español', ), `InformationURL` : A localized list of URLs where more information about the entity is located. 'InformationURL' => array( 'en' => 'http://example.com/info/en', 'es' => 'http://example.com/info/es', ), `PrivacyStatementURL` : A localized list of URLs where the entity's privacy statement is located. 'PrivacyStatementURL' => array( 'en' => 'http://example.com/privacy/en', 'es' => 'http://example.com/privacy/es', ), `Keywords` : A localized list of keywords used to describe the entity 'Keywords' => array( 'en' => array('communication', 'federated session'), 'es' => array('comunicación', 'sesión federated'), ), : *Note*: The `+` (plus) character is forbidden by specification from being part of a Keyword. `Logo` : The logos used to represent the entity 'Logo' => array( array( 'url' => 'http://example.com/logo1.png', 'height' => 200, 'width' => 400, 'lang' => 'en', ), array( 'url' => 'http://example.com/logo2.png', 'height' => 201, 'width' => 401, ), ), : An optional `lang` key containing a language-code is supported for localized logos. DiscoHints Items -------------- These elements are only relevant when operating in the IdP role; they assist IdP discovery to determine when to choose or present an IdP. These properties are all children of the `DiscoHints` key. `IPHint` : This is a list of both IPv4 and IPv6 addresses in CIDR notation services by or associated with this entity. 'IPHint' => array('130.59.0.0/16', '2001:620::0/96'), `DomainHint` : This specifies a list of domain names serviced by or associated with this entity. 'DomainHint' => array('example.com', 'www.example.com'), `GeolocationHint` : This specifies a list of geographic coordinates associated with, or serviced by, the entity. Coordinates are given in URI form using the geo URI scheme [RFC5870](http://www.ietf.org/rfc/rfc5870.txt). 'GeolocationHint' => array('geo:47.37328,8.531126', 'geo:19.34343,12.342514'), Generated XML Metadata Examples ---------------- If given the following configuration... $metadata['https://www.example.com/saml/saml2/idp/metadata.php'] = array( 'host' => 'www.example.com', 'certificate' => 'example.com.crt', 'privatekey' => 'example.com.pem', 'auth' => 'example-userpass', 'UIInfo' => array( 'DisplayName' => array( 'en' => 'English name', 'es' => 'Nombre en Español', ), 'Description' => array( 'en' => 'English description', 'es' => 'Descripción en Español', ), 'InformationURL' => array( 'en' => 'http://example.com/info/en', 'es' => 'http://example.com/info/es', ), 'PrivacyStatementURL' => array( 'en' => 'http://example.com/privacy/en', 'es' => 'http://example.com/privacy/es', ), 'Keywords' => array( 'en' => array('communication', 'federated session'), 'es' => array('comunicación', 'sesión federated'), ), 'Logo' => array( array( 'url' => 'http://example.com/logo1.png', 'height' => 200, 'width' => 400, ), array( 'url' => 'http://example.com/logo2.png', 'height' => 201, 'width' => 401, ), ), ), 'DiscoHints' => array( 'IPHint' => array('130.59.0.0/16', '2001:620::0/96'), 'DomainHint' => array('example.com', 'www.example.com'), 'GeolocationHint' => array('geo:47.37328,8.531126', 'geo:19.34343,12.342514'), ), ); ... will generate the following XML metadata: English name Nombre en Español English description Descripción en Español http://example.com/info/en http://example.com/info/es http://example.com/privacy/en http://example.com/privacy/es communication federated+session comunicación sesión+federated http://example.com/logo1.png http://example.com/logo2.png 130.59.0.0/16 2001:620::0/96 example.com www.example.com geo:47.37328,8.531126 geo:19.34343,12.342514 ... simplesamlphp-1.14.0/docs/simplesamlphp-scoping.txt0000644000000000000000000000720012660345056021166 0ustar rootrootScoping ======================== Scoping allows a service provider to specify a list of identity providers in an authnRequest to a proxying identity provider. This is an indication to the proxying identity provider that the service will only deal with the identity providers specified. A common use is for a service provider in a hub-and-spoke architecture to manage its own discovery service and being able to tell the hub/proxy-IdP which (backend-end) identity provider to use. The standard discovery service in SimpleSAMLphp will show the intersection of all the known IdPs and the IdPs specified in the scoping element. If this intersection only contains one IdP, then the request is automatically forwarded to that IdP. Scoping is a SAML 2.0 specific option. Options ------- SimpleSAMLphp supports scoping by allowing the following options: `ProxyCount` : Specifies the number of proxying indirections permissible between the identity provider receiving the request and the identity provider who ultimately authenticates the user. A count of zero permits no proxying. If ProxyCount is unspecified the number of proxy indirections is not limited. `IDPList` : The list of trusted IdPs, i.e. the list of entityIDs for identity providers that are relevant for a service provider in an authnRequest. ### Note ### SimpleSAMLphp does not support specifying the GetComplete option. Usage ----- The ProxyCount and IDPList option can be specified in the following places: - as a state parameter to the authentication source - in the saml:SP authentication source configuration - in the saml20-idp-remote metadata - in the saml20-sp-remote metadata Example configuration: # Add the IDPList 'IDPList' => array( 'IdPEntityID1', 'IdPEntityID2', 'IdPEntityID3', ), # Set ProxyCount 'ProxyCount' => 2, RequesterID element ------------------- To allow an identity provider to identify the original requester and the proxying identity providers, SimpleSAMLphp adds the RequesterID element to the request and if necessary the scoping element even if explicit scoping is not used. The RequesterId elements are available from the state array as an array, for instance the authenticate method in an authentication source $requesterIDs = $state['saml:RequesterID']; AuthenticatingAuthority element ------------------------------- To allow a service provider to identify the authentication authorities that were involved in the authentication of the user, SimpleSAMLphp adds the AuthenticatingAuthority elements. The list of authenticating authorities (the AuthenticatingAuthority element) can be retrieved as an array from the authentication data. # Get the authentication source. $as = new SimpleSAML_Auth_Simple(); # Get the AuthenticatingAuthority $aa = $as->getAuthData('saml:AuthenticatingAuthority'); Support ------- If you need help to make this work, or want to discuss SimpleSAMLphp with other users of the software, you are fortunate: Around SimpleSAMLphp there is a great Open source community, and you are welcome to join! The forums are open for you to ask questions, contribute answers other further questions, request improvements or contribute with code or plugins of your own. - [SimpleSAMLphp homepage](https://simplesamlphp.org) - [List of all available SimpleSAMLphp documentation](https://simplesamlphp.org/docs/) - [Join the SimpleSAMLphp user's mailing list](https://simplesamlphp.org/lists) simplesamlphp-1.14.0/docs/README0000644000000000000000000000041212660345056014765 0ustar rootrootUpdated: January 15th, 2015 All you need to know to install and configure simpleSAMLphp is available at: https://simplesamlphp.org/docs/ simpleSAMLphp homepage: https://simplesamlphp.org/ simpleSAMLphp mailinglist (for support): https://simplesamlphp.org/lists simplesamlphp-1.14.0/docs/simplesamlphp-upgrade-notes-1.8.txt0000644000000000000000000000120112660345056022600 0ustar rootrootUpgrade notes for SimpleSAMLphp 1.8 =================================== * The IdP now sends the NotOnOrAfter attribute in LogoutRequest messages. * We now have full support for selecting the correct AssertionConsumerService endpoint based on parameters in the authentication request. As a side effect of this, an IdP may start sending responses to a new AssertionConsumerService endpoint after upgrade. (This should only happen in the case where it sent the response to the wrong endpoint before.) * The SP no longer incorrectly returns PartialLogout as a status code in a LogoutResponse after the local session has expired. simplesamlphp-1.14.0/docs/index.txt0000644000000000000000000000714012660345056015762 0ustar rootrootSimpleSAMLphp Documentation =========================== * [Installing SimpleSAMLphp](simplesamlphp-install) * [Upgrade notes for version 1.14](simplesamlphp-upgrade-notes-1.14) * [Upgrade notes for version 1.13](simplesamlphp-upgrade-notes-1.13) * [Upgrade notes for version 1.12](simplesamlphp-upgrade-notes-1.12) * [Upgrade notes for version 1.11](simplesamlphp-upgrade-notes-1.11) * [Upgrade notes for version 1.10](simplesamlphp-upgrade-notes-1.10) * [Upgrade notes for version 1.9](simplesamlphp-upgrade-notes-1.9) * [Upgrade notes for version 1.8](simplesamlphp-upgrade-notes-1.8) * [Upgrade notes for version 1.7](simplesamlphp-upgrade-notes-1.7) * [Upgrade notes for version 1.6](simplesamlphp-upgrade-notes-1.6) * [Upgrade notes for version 1.5](simplesamlphp-upgrade-notes-1.5) * [Installation from the repository](simplesamlphp-install-repo) * [Changelog](simplesamlphp-changelog) * [Using SimpleSAMLphp as a SAML Service Provider](simplesamlphp-sp) * [Hosted SP Configuration Reference](./saml:sp) * [IdP remote reference](simplesamlphp-reference-idp-remote) * [Upgrading - migration to use the SAML authentication source](simplesamlphp-sp-migration) * [Configuring HTTP-Artifact](./simplesamlphp-artifact-sp) * [Using scoping](./simplesamlphp-scoping) * [Holder-of-Key profile](simplesamlphp-hok-sp) * [Identity Provider QuickStart](simplesamlphp-idp) * [IdP hosted reference](simplesamlphp-reference-idp-hosted) * [SP remote reference](simplesamlphp-reference-sp-remote) * [Use case: Setting up an IdP for Google Apps](simplesamlphp-googleapps) * [Configuring HTTP-Artifact](./simplesamlphp-artifact-idp) * [Identity Provider Advanced Topics](simplesamlphp-idp-more) * [Holder-of-Key profile](simplesamlphp-hok-idp) * [Automated Metadata Management](simplesamlphp-automated_metadata) * [Maintenance and configuration](simplesamlphp-maintenance) - covers session handling, php configuration etc. * [Authentication Processing Filters](simplesamlphp-authproc) - attribute filtering, attribute mapping, consent, group generation etc. * [Advanced features](simplesamlphp-advancedfeatures) - covers bridging protocols, attribute filtering, etc. * [State Information Lost](simplesamlphp-nostate) - more about this common error message * [SimpleSAMLphp Dictionaries and Translation](simplesamlphp-translation) * [Theming SimpleSAMLphp](simplesamlphp-theming) * [SimpleSAMLphp Modules](simplesamlphp-modules) - how to create own customized modules * [Key rollover](./saml:keyrollover) * [Creating authentication sources](./simplesamlphp-authsource) * [Implementing custom username/password authentication](./simplesamlphp-customauth) * [Storing sessions in Riak](./riak:simplesamlphp-riak) Documentation on specific SimpleSAMLphp modules: * [Consent module](./consent:consent) * [Installing and configuring the consentAdmin module](./consentAdmin:consentAdmin) * [Authorization](./authorize:authorize) * [autotest Module](./autotest:test) * [Statistics](./statistics:statistics) Documentation for SimpleSAMLphp developers: * [Error handling in SimpleSAMLphp](simplesamlphp-errorhandling) ## Externally contributed documentation * [Notes on using SimpleSAMLphp SP and Shibboleth IdP using SAML 2.0](http://www.zeitoun.net/articles/configure-simplesaml-1.3-sp-and-shibboleth-2.1-idp/start) ## Video tutorials * [Installation, configuration and test login with Feide (approx 8 minutes)](http://rnd.feide.no/content/video-tutorial-installing-and-configuring-simplesamlphp) ## Community help and support * [Please join the mailinglist](https://simplesamlphp.org/lists) simplesamlphp-1.14.0/docs/simplesamlphp-reference-idp-hosted.txt0000644000000000000000000003454412660345056023533 0ustar rootrootIdP hosted metadata reference ============================= This is a reference for the metadata files `metadata/saml20-idp-hosted.php` and `metadata/shib13-idp-hosted.php`. Both files have the following format: 'idp.example.org', /* Configuration options for the first IdP. */ ); $metadata['entity-id-2'] = array( 'host' => '__DEFAULT__', /* Configuration options for the default IdP. */ ); /* ... */ The entity ID should be an URI. It can, also be on the form `__DYNAMIC:1__`, `__DYNAMIC:2__`, `...`. In that case, the entity ID will be generated automatically. The `host` option is the hostname of the IdP, and will be used to select the correct configuration. One entry in the metadata-list can have the host `__DEFAULT__`. This entry will be used when no other entry matches. Common options -------------- `auth` : Which authentication module should be used to authenticate users on this IdP. `authproc` : Used to manipulate attributes, and limit access for each SP. See the [authentication processing filter manual](simplesamlphp-authproc). `certificate` : Certificate file which should be used by this IdP, in PEM format. The filename is relative to the `cert/`-directory. `host` : The hostname for this IdP. One IdP can also have the `host`-option set to `__DEFAULT__`, and that IdP will be used when no other entries in the metadata matches. `logouttype` : The logout handler to use. Either `iframe` or `traditional`. `traditional` is the default. `OrganizationName` : The name of the organization responsible for this IdP. This name does not need to be suitable for display to end users. : This option can be translated into multiple languages by specifying the value as an array of language-code to translated name: 'OrganizationName' => array( 'en' => 'Example organization', 'no' => 'Eksempel organisation', ), : *Note*: If you specify this option, you must also specify the `OrganizationURL` option. `OrganizationDisplayName` : The name of the organization responsible for this IdP. This name must be suitable for display to end users. If this option isn't specified, `OrganizationName` will be used instead. : This option can be translated into multiple languages by specifying the value as an array of language-code to translated name. : *Note*: If you specify this option, you must also specify the `OrganizationName` option. `OrganizationURL` : A URL the end user can access for more information about the organization. : This option can be translated into multiple languages by specifying the value as an array of language-code to translated URL. : *Note*: If you specify this option, you must also specify the `OrganizationName` option. `privacypolicy` : This is an absolute URL for where an user can find a privacypolicy. If set, this will be shown on the consent page. `%SPENTITYID%` in the URL will be replaced with the entity id of the service the user is accessing. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. `privatekey` : Name of private key file for this IdP, in PEM format. The filename is relative to the `cert/`-directory. `privatekey_pass` : Passphrase for the private key. Leave this option out if the private key is unencrypted. `scope` : An array with scopes for this IdP. The scopes will be added to the generated XML metadata. A scope can either be a domain name or a regular expression matching a number of domains. `userid.attribute` : The attribute name of an attribute which uniquely identifies the user. This attribute is used if SimpleSAMLphp needs to generate a persistent unique identifier for the user. This option can be set in both the IdP-hosted and the SP-remote metadata. The value in the sp-remote metadata has the highest priority. The default value is `eduPersonPrincipalName`. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. SAML 2.0 options ---------------- The following SAML 2.0 options are available: `assertion.encryption` : Whether assertions sent from this IdP should be encrypted. The default value is `FALSE`. : Note that this option can be set for each SP in the SP-remote metadata. `attributes.NameFormat` : What value will be set in the Format field of attribute statements. This parameter can be configured multiple places, and the actual value used is fetched from metadata by the following priority: : 1. SP Remote Metadata 2. IdP Hosted Metadata : The default value is: `urn:oasis:names:tc:SAML:2.0:attrname-format:basic` : Some examples of values specified in the SAML 2.0 Core Specification: : - `urn:oasis:names:tc:SAML:2.0:attrname-format:unspecified` - `urn:oasis:names:tc:SAML:2.0:attrname-format:uri` (The default in Shibboleth 2.0) - `urn:oasis:names:tc:SAML:2.0:attrname-format:basic` (The default in Sun Access Manager) : You can also define your own value. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. : (This option was previously named `AttributeNameFormat`.) `encryption.blacklisted-algorithms` : Blacklisted encryption algorithms. This is an array containing the algorithm identifiers. : Note that this option can be set for each SP in the [SP-remote metadata](./simplesamlphp-reference-sp-remote). : The RSA encryption algorithm with PKCS#1 v1.5 padding is blacklisted by default for security reasons. Any assertions encrypted with this algorithm will therefore fail to decrypt. You can override this limitation by defining an empty array in this option (or blacklisting any other algorithms not including that one). However, it is strongly discouraged to do so. For your own safety, please include the string 'http://www.w3.org/2001/04/xmlenc#rsa-1_5' if you make use of this option. `https.certificate` : The certificate used by the webserver when handling connections. This certificate will be added to the generated metadata of the IdP, which is required by some SPs when using the HTTP-Artifact binding. `nameid.encryption` : Whether NameIDs sent from this IdP should be encrypted. The default value is `FALSE`. : Note that this option can be set for each SP in the [SP-remote metadata](./simplesamlphp-reference-sp-remote). `NameIDFormat` : The format of the NameID supported by this IdP. Defaults to the `transient` format if unspecified. This parameter can be configured in multiple places, and the actual value used is fetched from metadata with the following priority: : 1. SP Remote Metadata 2. IdP Hosted Metadata : The three most commonly used values are: : 1. `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` 2. `urn:oasis:names:tc:SAML:2.0:nameid-format:persistent` 3. `urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress` : The `transient` format will generate a new unique ID every time the user logs in. : To properly support the `persistent` and `emailAddress` formats, you should configure [NameID generation filters](./saml:nameid) on your IdP. : Note that the value set here will be added to the metadata generated for this IdP, in the `NameIDFormat` element. `RegistrationInfo` : Allows to specify information about the registrar of this SP. Please refer to the [MDRPI extension](./simplesamlphp-metadata-extensions-rpi) document for further information. `saml20.sendartifact` : Set to `TRUE` to enable the IdP to send responses with the HTTP-Artifact binding. Defaults to `FALSE`. : Note that this requires a configured memcache server. `saml20.hok.assertion` : Set to `TRUE` to enable the IdP to send responses according the [Holder-of-Key Web Browser SSO Profile](./simplesamlphp-hok-idp). Defaults to `FALSE`. `saml20.sign.response` : Whether `` messages should be signed. Defaults to `TRUE`. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. `saml20.sign.assertion` : Whether `` elements should be signed. Defaults to `TRUE`. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. `sign.logout` : Whether to sign logout messages sent from this IdP. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. `SingleSignOnService` : Override the default URL for the SingleSignOnService for this IdP. This is an absolute URL. The default value is `/saml2/idp/SSOService.php` : Note that this only changes the values in the generated metadata and in the messages sent to others. You must also configure your webserver to deliver this URL to the correct PHP page. `SingleSignOnServiceBinding` : List of SingleSignOnService bindings that the IdP will claim support for. : Possible values: * `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect` * `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST` : Defaults to HTTP-Redirect binding. Please note that the order specified will be kept in the metadata, making the first binding the default one. `SingleLogoutService` : Override the default URL for the SingleLogoutService for this IdP. This is an absolute URL. The default value is `/saml2/idp/SingleLogoutService.php` : Note that this only changes the values in the generated metadata and in the messages sent to others. You must also configure your webserver to deliver this URL to the correct PHP page. `SingleLogoutServiceBinding` : List of SingleLogoutService bindings the IdP will claim support for. : Possible values: * `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect` * `urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST` : Defaults to HTTP-Redirect binding. Please note that the order specified will be kept in the metadata, making the first binding the default one. `signature.algorithm` : The algorithm to use when signing any message generated by this identity provider. Defaults to RSA-SHA1. : Possible values: * `http://www.w3.org/2000/09/xmldsig#rsa-sha1` *Note*: the use of SHA1 is **deprecated** and will be disallowed in the future. * `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` `validate.authnrequest` : Whether we require signatures on authentication requests sent to this IdP. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. `validate.logout` : Whether we require signatures on logout messages sent to this IdP. : Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. ### Fields for signing and validating messages SimpleSAMLphp only signs authentication responses by default. Signing of logout requests and logout responses can be enabled by setting the `redirect.sign` option. Validation of received messages can be enabled by the `redirect.validate` option. These options set the default for this IdP, but options for each SP can be set in `saml20-sp-remote`. Note that you need to add a certificate for each SP to be able to validate signatures on messages from that SP. `redirect.sign` : Whether logout requests and logout responses sent from this IdP should be signed. The default is `FALSE`. `redirect.validate` : Whether authentication requests, logout requests and logout responses received sent from this IdP should be validated. The default is `FALSE` **Example: Configuration for signed messages** 'redirect.sign' => true, Shibboleth 1.3 options ---------------------- The following options for Shibboleth 1.3 IdP's are avaiblable: `scopedattributes` : Array with names of attributes which should be scoped. Scoped attributes will receive a `Scope`-attribute on the `AttributeValue`-element. The value of the Scope-attribute will be taken from the attribute value: : `someuser@example.org` : will be transformed into : `someuser` : By default, no attributes are scoped. Note that this option also exists in the SP-remote metadata, and any value in the SP-remote metadata overrides the one configured in the IdP metadata. Metadata extensions ------------------- SimpleSAMLphp supports generating metadata with the MDUI, MDRPI and EntityAttributes metadata extensions. See the documentation for those extensions for more details: * [MDUI extension](./simplesamlphp-metadata-extensions-ui) * [MDRPI extension](./simplesamlphp-metadata-extensions-rpi) * [EntityAttributes](./simplesamlphp-metadata-extensions-attributes) Examples -------- These are some examples of IdP metadata ### Minimal SAML 2.0 / Shibboleth 1.3 IdP ### '__DEFAULT__', /* The private key and certificate used by this IdP. */ 'certificate' => 'example.org.crt', 'privatekey' => 'example.org.pem', /* * The authentication source for this IdP. Must be one * from config/authsources.php. */ 'auth' => 'example-userpass', ); simplesamlphp-1.14.0/docs/simplesamlphp-authproc.txt0000644000000000000000000002525712660345056021365 0ustar rootrootAuthentication Processing Filters in SimpleSAMLphp ================================================== In SimpleSAMLphp, there is an API where you can *do stuff* at the IdP after authentication is complete, and just before you are sent back to the SP. The same API is available on the SP, after you have received a successful Authentication Response from the IdP and before you are sent back to the SP application. Authentication processing filters postprocess authentication information received from authentication sources. It is possible to use this for additional authentication checks, requesting the user's consent before delivering attributes about the user, modifying the user's attributes, and other things which should be performed before returning the user to the service provider he came from. Examples of neat things to do using Authentication Processing Filters: * Filter out a subset of available attributes that are sent to a SP. * Modify the name of attributes. * Generate new attributes that are composed of others, for example eduPersonTargetedID. * Ask the user for consent, before the user is sent back to a service. * Implement basic Access Control on the IdP (not neccessarily a good idea), limiting access for some users to some SPs. Be aware that Authentication Proccessing Filters do replace some of the preivous features in SimpleSAMLphp, named: * `attributemap` * `attributealter` * attribute filter Later in this document, we will desribe in detail the alternative Authentication Proccessing Filters that will replicate these functionalities. How to configure Auth Proc Filters ---------------------------------- *Auth Proc Filters* can be set globally, or to be specific for only one SP or one IdP. That means there are five locations where you can configure *Auth Proc Filters*: * Globally in `config.php` * On the SP: Specific for only the SP in `authsources.php` * On the SP: Specific for only one remote IdP in `saml20-idp-remote` or `shib13-idp-remote` * On the IdP: Specific for only one hosted IdP in `saml20-idp-hosted` or `shib13-idp-hosted` * On the IdP: Specific for only one remote SP in `saml20-sp-remote` or `shib13-sp-remote` The configuration of *Auth Proc Filters* is a list of filters with priority as *index*. Here is an example of *Auth Proc Filters* configured in `config.php`: 'authproc.idp' => array( 10 => array( 'class' => 'core:AttributeMap', 'addurnprefix' ), 20 => 'core:TargetedID', 40 => 'core:AttributeRealm', 50 => 'core:AttributeLimit', 90 => array( 'class' => 'consent:Consent', 'store' => 'consent:Cookie', 'focus' => 'yes', 'checked' => TRUE ), ), This configuration will execute *Auth Proc Filters* one by one, with the priority value in increasing order. When *Auth Proc Filters* is configured in multiple places, in example both globally, in the hosted IdP and remote SP metadata, then the list is interleaved sorted by priority. The most important parameter of each item on the list is the *class* of the *Auth Proc Filter*. The syntax of the class is `modulename:classname`. As an example the class definition `core:AttributeLimit` will be expanded to look for the class `sspmod_core_Auth_Process_AttributeLimit`. The location of this class file *must* then be: `modules/core/lib/Auth/Process/AttributeLimit.php`. You will see that a bunch of useful filters is included in the `core` module. In addition the `consent` module that is included in the SimpleSAMLphp distribution implements a filter. Beyond that, you are encouraged to create your own filters and share with the community. If you have created a cool *Auth Proc Filter* that does something useful, let us know, and we may share it on the [SimpleSAMLphp web site][]. [SimpleSAMLphp web site]: http://simplesamlphp.org When you know the class definition of a filter, and the priority, the simple way to configure the filter is: 20 => 'core:TargetedID', This is analogous to: 20 => array( 'class' => 'core:TargetedID' ), Some *Auth Proc Filters* have optional or required *parameters*. To send parameters to *Auth Proc Filters*, you need to choose the second of the two alernatives above. Here is an example of provided parameters to the consent module: 90 => array( 'class' => 'consent:Consent', 'store' => 'consent:Cookie', 'focus' => 'yes', 'checked' => TRUE ), ### Filters in `config.php` Global *Auth Proc Filters* are configured in the `config.php` file. You will see that the config template already includes an example configuration. There are two config parameters: * `authproc.idp` and * `authproc.sp` The filters in `authproc.idp` will be executed at the IdP side regardless of which IdP and SP entity that is involved. The filters in `authproc.sp` will be executed at the SP side regardless of which SP and IdP entity that is involved. ### Filters in metadata Filters can be added both in `hosted` and `remote` metadata. Here is an example of a filter added in a metadata file: '__DYNAMIC:1__' => array( 'host' => '__DEFAULT_', 'privatekey' => 'example.org.pem', 'certificate' => 'example.org.crt', 'auth' => 'feide', 'authproc' => array( 40 => 'core:AttributeRealm', ), ) The example above is in `saml20-idp-hosted`. Auth Proc Filters included in the SimpleSAMLphp distribution ------------------------------------------------------------ The following filters are included in the SimpleSAMLphp distribution: - [`authorize:Authorize`](./authorize:authorize): Access control based on regular expressions. - [`consent:Consent`](./consent:consent): Ask the user for consent before transmitting attributes. - [`core:AttributeAdd`](./core:authproc_attributeadd): Add attributes to the response. - [`core:AttributeCopy`](./core:authproc_attributecopy): Copy existing attributes to the response. - [`core:AttributeAlter`](./core:authproc_attributealter): Do search-and-replace on attributevalues. - [`core:AttributeLimit`](./core:authproc_attributelimit): Limit the attributes in the response. - [`core:AttributeMap`](./core:authproc_attributemap): Change the name of the attributes. - [`core:AttributeRealm`](./core:authproc_attributerealm): Create an attribute with the realm of the user. - [`core:GenerateGroups`](./core:authproc_generategroups): Generate a `group` attribute for the user. - [`core:LanguageAdaptor`](./core:authproc_languageadaptor): Transfering language setting from IdP to SP. - [`core:PHP`](./core:authproc_php): Modify attributes with custom PHP code. - [`core:ScopeAttribute`](./core:authproc_scopeattribute): Add scope to attribute. - [`core:ScopeFromAttribute`](./core:authproc_scopefromattribute): Create a new attribute based on the scope on a different attribute. - [`core:StatisticsWithAttribute`](./core:authproc_statisticswithattribute): Create a statistics logentry. - [`core:TargetedID`](./core:authproc_targetedid): Generate the `eduPersonTargetedID` attribute. - [`core:WarnShortSSOInterval`](./core:authproc_warnshortssointerval): Give a warning if the user logs into the same SP twice within a few seconds. - [`expirycheck:ExpiryDate`](./expirycheck:expirycheck): Block access to accounts that have expired. - [`preprodwarning:Warning`](./preprodwarning:warning): Warn the user about accessing a test IdP. - [`saml:AttributeNameID`](./saml:nameid): Generate custom NameID with the value of an attribute. - [`saml:ExpectedAuthnContextClassRef`](./saml:authproc_expectedauthncontextclassref): Verify the user's authentication context. - [`saml:NameIDAttribute`](./saml:nameidattribute): Create an attribute based on the NameID we receive from the IdP. - [`saml:PersistentNameID`](./saml:nameid): Generate persistent NameID from an attribute. - [`saml:PersistentNameID2TargetedID`](./saml:nameid): Store persistent NameID as eduPersonTargetedID. - [`saml:TransientNameID`](./saml:nameid): Generate transient NameID. - [`smartattributes:SmartID`](./smartattributes:smartattributes): Generate user ID attribute based on several attributes. Writing your own Auth Proc Filter --------------------------------- Look at the included *Auth Proc Filters* as examples. Copy the classes into your own module and start playing around. Authentication processing filters are created by creating a class under `Auth/Process/` in a module. This class is expected to subclass `SimpleSAML_Auth_ProcessingFilter`. A filter must implement at least one function - the `process(&$request)`-function. This function can access the `$request`-array to add, delete and modify attributes, and can also do more advanced processing based on the SP/IdP metadata (which is also included in the `$request`-array). When this function returns, it is assumed that the filter has finished processing. If a filter for some reason needs to redirect the user, for example to show a web page, it should save the current request. Upon completion it should retrieve the request, update it with the changes it is going to make, and call `SimpleSAML_Auth_ProcessingChain::resumeProcessing`. This function will continue processing the next configured filter. Requirements for authentication processing filters: - Must be derived from the `SimpleSAML_Auth_ProcessingFilter`-class. - If a constructor is implemented, it must first call the parent constructor, passing along all parameters, before accessing any of the parameters. In general, only the $config parameter should be accessed. - The `process(&$state)`-function must be implemented. If this function completes, it is assumed that processing is completed, and that the $request array has been updated. - If the `process`-function does not return, it must at a later time call `SimpleSAML_Auth_ProcessingChain::resumeProcessing` with the new request state. The request state must be an update of the array passed to the `process`-function. - No pages may be shown to the user from the `process`-function. Instead, the request state should be saved, and the user should be redirected to a new page. This must be done to prevent unpredictable events if the user for example reloads the page. - No state information should be stored in the filter object. It must instead be stored in the request state array. Any changes to variables in the filter object may be lost. - The filter object must be serializable. It may be serialized between being constructed and the call to the `process`-function. This means that, for example, no database connections should be created in the constructor and later used in the `process`-function. Don't hestitate to ask on the SimpleSAMLphp mailinglist if you have problems or questions, or want to share your *Auth Proc Filter* with others. simplesamlphp-1.14.0/docs/simplesamlphp-googleapps.txt0000644000000000000000000002460212660345056021671 0ustar rootrootSetting up a SimpleSAMLphp SAML 2.0 IdP to use with Google Apps for Education ============================================ SimpleSAMLphp news and documentation ------------------------------------ This document is part of the SimpleSAMLphp documentation suite. * [List of all SimpleSAMLphp documentation](http://simplesamlphp.org/docs) * [SimpleSAMLphp homepage](https://simplesamlphp.org) ## Introduction This article assumes that you have already read the SimpleSAMLphp installation manual, and installed a version of SimpleSAMLphp at your server. In this example we will setup this server as an IdP for Google Apps for Education: dev2.andreas.feide.no ## Enabling the Identity Provider functionality Edit `config.php`, and enable the SAML 2.0 IdP: 'enable.saml20-idp' => true, 'enable.shib13-idp' => false, ## Setting up a SSL signing certificate For test purposes, you can skip this section, and use the certificate included in the SimpleSAMLphp distribution. For a production system, you MUST generate a new certificate for your IdP. Here is an example of an openssl command to generate a new key and a self signed certificate to use for signing SAML messages: openssl req -newkey rsa:2048 -new -x509 -days 3652 -nodes -out googleappsidp.crt -keyout googleappsidp.pem The certificate above will be valid for 10 years. Here is an example of typical user input when creating a certificate request: Country Name (2 letter code) [AU]:NO State or Province Name (full name) [Some-State]:Trondheim Locality Name (eg, city) []:Trondheim Organization Name (eg, company) [Internet Widgits Pty Ltd]:UNINETT Organizational Unit Name (eg, section) []: Common Name (eg, YOUR name) []:dev2.andreas.feide.no Email Address []: Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []: **Note**: SimpleSAMLphp will only work with RSA and not DSA certificates. Authentication source --------------------- The next step is to configure the way users authenticate on your IdP. Various modules in the `modules/` directory provides methods for authenticating your users. This is an overview of those that are included in the SimpleSAMLphp distribution: `exampleauth:UserPass` : Authenticate against a list of usernames and passwords. `exampleauth:Static` : Automatically log in as a user with a set of attributes. [`ldap:LDAP`](./ldap:ldap) : Authenticates an user to a LDAP server. For more authentication modules, see [SimpleSAMLphp Identity Provider QuickStart](simplesamlphp-idp). In this guide, we will use the `exampleauth:UserPass` authentication module. This module does not have any dependencies, and is therefore simple to set up. After you have successfuly tested that everything is working with the simple `exampleauth:UserPass`, you are encouraged to setup SimpleSAMLphp IdP towards your user storage, such as an LDAP directory. (Use the links on the authentication sources above to read more about these setups. `ldap:LDAP` is the most common authentication source). Configuring the authentication source ------------------------------------- The `exampleauth:UserPass` authentication source is part of the `exampleauth` module. This module isn't enabled by default, so you will have to enable it. This is done by creating a file named `enable` in `modules/exampleauth/`. On unix, this can be done by running (from the SimpleSAMLphp installation directory): touch modules/exampleauth/enable The next step is to create an authentication source with this module. An authentication source is an authentication module with a specific configuration. Each authentication source has a name, which is used to refer to this specific configuration in the IdP configuration. Configuration for authentication sources can be found in `config/authsources.php`. In this example we will use the `example-userpass`, and hence that section is what matters and will be used. array( 'exampleauth:UserPass', 'student:studentpass' => array( 'uid' => array('student'), ), 'employee:employeepass' => array( 'uid' => array('employee'), ), ), ); ?> This configuration creates two users - `student` and `employee`, with the passwords `studentpass` and `employeepass`. The username and password is stored in the array index `student:studentpass` for the `student`-user. The attributes (only `uid` in this example) will be returned by the IdP when the user logs on. ## Configuring metadata for an SAML 2.0 IdP If you want to setup a SAML 2.0 IdP for Google Apps, you need to configure two metadata files: `saml20-idp-hosted.php` and `saml20-sp-remote.php`. ### Configuring SAML 2.0 IdP Hosted metadata This is the configuration of the IdP itself. Here is some example config: // The SAML entity ID is the index of this config. Dynamic:X will automatically generate an entity ID (Reccomended) $metadata['__DYNAMIC:1__'] => array( // The hostname of the server (VHOST) that this SAML entity will use. 'host' => '__DEFAULT__', // X.509 key and certificate. Relative to the cert directory. 'privatekey' => 'googleappsidp.pem', 'certificate' => 'googleappsidp.crt', 'auth' => 'example-userpass', ) **Note**: You can only have one entry in the file with host equal `__DEFAULT__`, therefore you should replace the existing entry with this one, instead of adding this entry as a new entry in the file. ### Configuring SAML 2.0 SP Remote metadata In the (`saml20-sp-remote.php`) file we will configure an entry for Google Apps for education. There is already an entry for Google Apps in the template, but we will change the domain name: /* * This example shows an example config that works with Google Apps for education. * What is important is that you have an attribute in your IdP that maps to the local part of the email address * at Google Apps. E.g. if your google account is foo.com, and you have a user with email john@foo.com, then you * must set the simplesaml.nameidattribute to be the name of an attribute that for this user has the value of 'john'. */ $metadata['google.com'] => array( 'AssertionConsumerService' => 'https://www.google.com/a/g.feide.no/acs', 'NameIDFormat' => 'urn:oasis:names:tc:SAML:1.1:nameid-format:emailAddress', 'simplesaml.nameidattribute' => 'uid', 'simplesaml.attributes' => false ); You must also map some attributes received from the authentication module into email field sent to Google Apps. In this example, the `uid` attribute is set. When you later configure the IdP to connect to a LDAP directory or some other authentication source, make sure that the `uid` attribute is set properly, or you can configure another attribute to use here. The `uid` attribute contains the local part of the user name. For an e-mail address `student@g.feide.no`, the `uid` should be set to `student`. You should modify the `AssertionConsumerService` to include your Google Apps domain name instead of `g.feide.no`. For an explanation of the parameters, see the [SimpleSAMLphp Identity Provider QuickStart](simplesamlphp-idp). ## Configure Google Apps for education Start by logging in to our Google Apps for education account panel. Then select "Advanced tools": **Figure 1. We go to advanced tools** ![We go to advanced tools](resources/simplesamlphp-googleapps/googleapps-menu.png) Then select "Set up single sign-on (SSO)": **Figure 2. We go to setup SSO** ![We go to setup SSO](resources/simplesamlphp-googleapps/googleapps-sso.png) Upload a certificate, such as the googleappsidp.crt created above: **Figure 3. Uploading certificate** ![Uploading certificate](resources/simplesamlphp-googleapps/googleapps-cert.png) Fill out the remaining fields: The most important field is the Sign-in page URL. Set it to something similar to: http://dev2.andreas.feide.no/simplesaml/saml2/idp/SSOService.php using the hostname of your IdP server. You must also configure the IdP initiated Single LogOut endpoint of your server. The RelayState parameter of the endpoint is the URL where the user is redirected after successfull logout. Recommended value: http://dev2.andreas.feide.no/simplesaml/saml2/idp/initSLO.php?RelayState=/simplesaml/logout.php again, using the host name of your IdP server. The Sign-out page or change password URL can be static pages on your server. The network mask determines which IP addresses will be asked for SSO login. IP addresses not matching this mask will be presented with the normal Google Apps login page. I think you can leave this field empty to enable authentication for all URLs. **Figure 4. Fill out the remaining fields** ![Fill out the remaining fields](resources/simplesamlphp-googleapps/googleapps-ssoconfig.png) ### Add a user in Google Apps that is known to the IdP Before we can test login, a new user must be defined in Google Apps. This user must have a mail field matching the email prefix mapped from the attribute as described above in the metadata section. ## Test to login to Google Apps for education Go to the URL of your mail account for this domain, the URL is similar to the following: http://mail.google.com/a/yourgoogleappsdomain.com replacing the last part with your own google apps domain name. ## Security Considerations Make sure that your IdP server runs HTTPS (SSL). The Apache documentation contains information for how to configure HTTPS. Make sure you have replaced the default certificate delivered with the SimpleSAMLphp distribution with your own certificate. Support ------- If you need help to make this work, or want to discuss SimpleSAMLphp with other users of the software, you are fortunate: Around SimpleSAMLphp there is a great Open source community, and you are welcome to join! The forums are open for you to ask questions, contribute answers other further questions, request improvements or contribute with code or plugins of your own. - [SimpleSAMLphp homepage](https://simplesamlphp.org) - [List of all available SimpleSAMLphp documentation](https://simplesamlphp.org/docs/) - [Join the SimpleSAMLphp user's mailing list](https://simplesamlphp.org/lists) simplesamlphp-1.14.0/docs/simplesamlphp-authsource.txt0000644000000000000000000001326112660345056021712 0ustar rootrootCreating authentication sources =============================== All authentication sources are located in the `lib/Auth/Source/` directory in a module, and the class name is `sspmod__Auth_Source_`. The authentication source must extend the `SimpleSAML_Auth_Source` class or one of its subclasses. The "entry point" of an authentication source is the `authenticate()`-function. Once that function is called, the authentication module can do whatever it wishes to do. There are only two requirements: - Never show any pages to the user directly from within the `authenticate()`-function. (This will lead to problems if the user decides to reload the page.) - Return control to SimpleSAMLphp after authenticating the user. If the module is able to authenticate the user without doing any redirects, it should just update the state-array and return. If the module does a redirect, it must call `SimpleSAML_Auth_Source::completeAuth()` with the updated state array. Everything else is up to the module. If the module needs to redirect the user, for example because it needs to show the user a page asking for credentials, it needs to save the state array. For that we have the `SimpleSAML_Auth_State` class. This is only a convenience class, and you are not required to use it (but its use is encouraged, since it handles some potential pitfalls). Saving state ------------ The `SimpleSAML_Auth_State` class has two functions that you should use: `saveState($state, $stage)`, and `loadState($id, $stage)`. The `$stage` parameter must be an unique identifier for the current position in the authentication. It is used to prevent a malicious user from taking a state you save in one location, and give it to a different location. The `saveState()`-function returns an id, which you should pass to the `loadState()`-function later. Username/password authentication -------------------------------- Since username/password authentication is quite a common operation, a base class has been created for this. This is the `sspmod_core_Auth_UserPassBase` class, which is can be found as `modules/core/lib/Auth/UserPassBase.php`. The only function you need to implement is the `login($username, $password)`-function. This function receives the username and password the user entered, and is expected to return the attributes of that user. If the username or password is incorrect, it should throw an error saying so: throw new SimpleSAML_Error_Error('WRONGUSERPASS'); "[Implementing custom username/password authentication](./simplesamlphp-customauth)" describes how to implement username/password authentication using that base class. Generic rules & requirements ---------------------------- - Must be derived from the `SimpleSAML_Auth_Source`-class. **Rationale**: - Deriving all authentication sources from a single base class allows us extend all authentication sources by extending the base class. - If a constructor is implemented, it must first call the parent constructor, passing along all parameters, before accessing any of the parameters. In general, only the $config parameter should be accessed when implementing the authentication source. **Rationale**: - PHP doesn't automatically call any parent constructor, so it needs to be done manually. - The `$info`-array is used to provide information to the `SimpleSAML_Auth_Source` base class, and therefore needs to be included. - Including the `$config`-array makes it possible to add generic configuration options that are valid for all authentication sources. - The `authenticate(&$state)`-function must be implemented. If this function completes, it is assumed that the user is authenticated, and that the `$state`-array has been updated with the user's attributes. **Rationale**: - Allowing the `authenticate()`-function to return after updating the `$state`-array enables us to do authentication without redirecting the user. This can be used if the authentication doesn't require user input, for example if the authentication can be done based on the IP-address of the user. - If the `authenticate`-function does not return, it must at a later time call `SimpleSAML_Auth_Source::completeAuth` with the new state array. The state array must be an update of the array passed to the `authenticate`-function. **Rationale**: - Preserving the same state array allows us to save information in that array before the authentication starts, and restoring it when authentication completes. - No pages may be shown to the user from the `authenticate()`-function. Instead, the state should be saved, and the user should be redirected to a new page. **Rationale**: - The `authenticate()`-function is called in the context of a different PHP page. If the user reloads that page, unpredictable results may occur. - No state information about any authentication should be stored in the authentication source object. It must instead be stored in the state array. Any changes to variables in the authentication source object may be lost. **Rationale**: - This saves us from having to save the entire authentication object between requests. Instead, we can recreate it from the configuration. - The authentication source object must be serializable. It may be serialized between being constructed and the call to the `authenticate()`-function. This means that, for example, no database connections should be created in the constructor and later used in the `authenticate()`-function. **Rationale**: - If parsing the configuration and creating the authentication object is shown to be a bottleneck, we can cache an initialized authentication source. simplesamlphp-1.14.0/docs/simplesamlphp-modules.txt0000644000000000000000000002125212660345056021177 0ustar rootrootSimpleSAMLphp modules ================================================== This document describes how the module system in SimpleSAMLphp works. It descibes what types of modules there are, how they are configured, and how to write new modules. Overview -------- There are currently three parts of SimpleSAMLphp which can be stored in modules - authentication sources, authentication processing filters and themes. There is also support for defining hooks - functions run at specific times. More than one thing can be stored in a single module. There is also support for storing supporting files, such as templates and dictionaries, in modules. The different functionalities which can be created as modules will be described in more detail in the following sections; what follows is a short introduction to what you can du with them: - Authentication sources implement different methods for authenticating users, for example simple login forms which authenticate against a database backend, or login methods which use client-side certificates. - Authentication processing filters perform various tasks after the user is authenticated and has a set of attributes. They can add, remove and modify attributes, do additional authentication checks, ask questions of the user, +++. - Themes allow you to package custom templates for multiple modules into a single module. ## Module layout Each SimpleSAMLphp module is stored in a directory under the the `modules`-directory. The module directory contains the following directories and files: default-disable : The presence of this file indicates that the module is disabled by default. This module can be enabled by creating a file named `enable` in the same directory. default-enable : The presence of this file indicates that the module is enabled by default. This module can be disabled by creating a file named `disable` in the same directory. dictionaries : This directory contains dictionaries which belong to this module. To use a dictionary stored in a module, the extended tag names can be used: `{::}` For example, `{example:login:hello}` will look up `hello` in `modules/example/dictionaries/login.php`. : It is also possible to specify `:` as the default dictionary when instantiating the `SimpleSAML_XHTML_Template` class. hooks : This directory contains hook functions for this module. Each file in this directory represents a single function. See the hook-section in the documentation for more information. lib : This directory contains classes which belong to this module. All classes must be named in the following pattern: `sspmod__` When looking up the filename of a class, SimpleSAMLphp will search for `` in the `lib` directory. Underscores in the class name will be translated into slashes. : Thus, if SimpleSAMLphp needs to load a class named `sspmod_example_Auth_Source_Example`, it will load the file named `modules/example/lib/Auth/Source/Example.php`. templates : These are module-specific templates. To use one of these templates, specify `: