Skip to content

Commit 6bc954d

Browse files
committed
CPS-175
[CPS-175](https://workivate.atlassian.net/browse/CPS-175) Merge upstream for latest stable changes
2 parents 5615c61 + b22a57e commit 6bc954d

22 files changed

+1385
-2083
lines changed

.github/workflows/php-package.yml

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# This workflow will install PHP dependencies, run tests and lint with a variety of PHP versions
2+
# For more information see: https://github.com/marketplace/actions/setup-php-action
3+
4+
name: php-saml 4.x package
5+
6+
on:
7+
push:
8+
branches: [ 4.* ]
9+
pull_request:
10+
branches: [ 4.* ]
11+
12+
jobs:
13+
test:
14+
runs-on: ${{ matrix.operating-system }}
15+
strategy:
16+
fail-fast: false
17+
matrix:
18+
operating-system: ['ubuntu-latest']
19+
php-versions: [7.3, 7.4, 8.0, 8.1]
20+
steps:
21+
- name: Setup PHP, with composer and extensions
22+
uses: shivammathur/setup-php@v2 #https://github.com/shivammathur/setup-php
23+
with:
24+
php-version: ${{ matrix.php-versions }}
25+
extensions: mbstring, intl, mcrypt, xml
26+
tools: composer:v2
27+
ini-values: post_max_size=256M, max_execution_time=180
28+
coverage: xdebug
29+
30+
- name: Set git to use LF
31+
run: |
32+
git config --global core.autocrlf false
33+
git config --global core.eol lf
34+
- uses: actions/checkout@v2
35+
36+
- name: Validate composer.json and composer.lock
37+
run: composer validate
38+
39+
- name: Install Composer dependencies
40+
run: |
41+
composer self-update
42+
composer install --prefer-source --no-interaction
43+
- name: Syntax check PHP
44+
run: |
45+
php vendor/bin/phpcpd --exclude tests --exclude vendor .
46+
php vendor/bin/phploc src/.
47+
mkdir -p tests/build/dependences
48+
php vendor/bin/pdepend --summary-xml=tests/build/logs/dependence-summary.xml --jdepend-chart=tests/build/dependences/jdepend.svg --overview-pyramid=tests/build/dependences/pyramid.svg src/.
49+
50+
- name: PHP Code Sniffer
51+
run: php vendor/bin/phpcs --standard=tests/ZendModStandard src/Saml2 demo1 demo2 endpoints tests/src
52+
53+
- name: Run unit tests
54+
run: vendor/bin/phpunit --verbose --debug

README.md

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,37 @@ environment is not secure and will be exposed to attacks.
148148

149149
In production also we highly recommended to register on the settings the IdP certificate instead of using the fingerprint method. The fingerprint, is a hash, so at the end is open to a collision attack that can end on a signature validation bypass. Other SAML toolkits deprecated that mechanism, we maintain it for compatibility and also to be used on test environment.
150150

151+
152+
### Avoiding Open Redirect attacks ###
153+
154+
Some implementations uses the RelayState parameter as a way to control the flow when SSO and SLO succeeded. So basically the
155+
user is redirected to the value of the RelayState.
156+
157+
If you are using Signature Validation on the HTTP-Redirect binding, you will have the RelayState value integrity covered, otherwise, and
158+
on HTTP-POST binding, you can't trust the RelayState so before
159+
executing the validation, you need to verify that its value belong
160+
a trusted and expected URL.
161+
162+
Read more about Open Redirect [CWE-601](https://cwe.mitre.org/data/definitions/601.html).
163+
164+
165+
### Avoiding Reply attacks ###
166+
167+
A reply attack is basically try to reuse an intercepted valid SAML Message in order to impersonate a SAML action (SSO or SLO).
168+
169+
SAML Messages have a limited timelife (NotBefore, NotOnOrAfter) that
170+
make harder this kind of attacks, but they are still possible.
171+
172+
In order to avoid them, the SP can keep a list of SAML Messages or Assertion IDs alredy valdidated and processed. Those values only need
173+
to be stored the amount of time of the SAML Message life time, so
174+
we don't need to store all processed message/assertion Ids, but the most recent ones.
175+
176+
The OneLogin_Saml2_Auth class contains the [getLastRequestID](https://github.com/onelogin/php-saml/blob/b8214b74dd72960fa6aa88ab454667c64cea935c/src/Saml2/Auth.php#L657), [getLastMessageId](https://github.com/onelogin/php-saml/blob/b8214b74dd72960fa6aa88ab454667c64cea935c/src/Saml2/Auth.php#L762) and [getLastAssertionId](https://github.com/onelogin/php-saml/blob/b8214b74dd72960fa6aa88ab454667c64cea935c/src/Saml2/Auth.php#L770) methods to retrieve the IDs
177+
178+
Checking that the ID of the current Message/Assertion does not exists in the list of the ones already processed will prevent reply
179+
attacks.
180+
181+
151182
Getting started
152183
---------------
153184

@@ -754,6 +785,8 @@ $_SESSION['samlNameidSPNameQualifier'] = $auth->getNameIdSPNameQualifier();
754785
$_SESSION['samlSessionIndex'] = $auth->getSessionIndex();
755786

756787
if (isset($_POST['RelayState']) && OneLogin\Saml2\Utils::getSelfURL() != $_POST['RelayState']) {
788+
// To avoid 'Open Redirect' attacks, before execute the
789+
// redirection confirm the value of $_POST['RelayState'] is a // trusted URL.
757790
$auth->redirectTo($_POST['RelayState']);
758791
}
759792

@@ -1092,6 +1125,8 @@ if (isset($_GET['sso'])) { // SSO action. Will send an AuthNRequest to the I
10921125

10931126
$_SESSION['samlUserdata'] = $auth->getAttributes(); // Retrieves user data
10941127
if (isset($_POST['RelayState']) && OneLogin\Saml2\Utils::getSelfURL() != $_POST['RelayState']) {
1128+
// To avoid 'Open Redirect' attacks, before execute the
1129+
// redirection confirm the value of $_POST['RelayState'] is a // trusted URL.
10951130
$auth->redirectTo($_POST['RelayState']); // Redirect if there is a
10961131
} // relayState set
10971132
} else if (isset($_GET['sls'])) { // Single Logout Service
@@ -1100,7 +1135,7 @@ if (isset($_GET['sso'])) { // SSO action. Will send an AuthNRequest to the I
11001135
if (empty($errors)) {
11011136
echo '<p>Sucessfully logged out</p>';
11021137
} else {
1103-
echo '<p>' . implode(', ', $errors) . '</p>';
1138+
echo '<p>' . htmlentities(implode(', ', $errors)) . '</p>';
11041139
}
11051140
}
11061141

@@ -1384,6 +1419,8 @@ Auxiliary class that contains several methods to retrieve and process IdP metada
13841419
* `parseXML` - Get IdP Metadata Info from XML.
13851420
* `injectIntoSettings` - Inject metadata info into php-saml settings array.
13861421

1422+
The class does not validate in any way the URL that is introduced on methods like parseRemoteXML in order to retrieve the remove XML. Usually is the same administrator that handles the Service Provider the ones that set the URL that should belong to a trusted third-party IdP.
1423+
But there are other scenarios, like a SAAS app where the administrator of the app delegates on other administrators. In such case, extra protection should be taken in order to validate such URL inputs and avoid attacks like SSRF.
13871424

13881425
For more info, look at the source code; each method is documented and details
13891426
about what it does and how to use it are provided. Make sure to also check the doc folder where

composer.json

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,13 +19,17 @@
1919
"robrichards/xmlseclibs": ">=3.1.1"
2020
},
2121
"require-dev": {
22-
"phpunit/phpunit": "^9.5.2",
22+
"phpunit/phpunit": "^9.5",
2323
"php-coveralls/php-coveralls": "^2.0",
24+
"sebastian/phpcpd": "^4.0 || ^5.0 || ^6.0 ",
25+
"phploc/phploc": "^4.0 || ^5.0 || ^6.0 || ^7.0",
2426
"pdepend/pdepend": "^2.8.0",
25-
"squizlabs/php_codesniffer": "^3.5.8",
26-
"vimeo/psalm": "^4.6"
27+
"squizlabs/php_codesniffer": "^3.5.8"
2728
},
2829
"config": {
30+
"platform": {
31+
"php": "7.3.0"
32+
},
2933
"optimize-autoloader": true,
3034
"sort-packages": true
3135
},

0 commit comments

Comments
 (0)