Skip to content

Commit d1a5c13

Browse files
TatevikGrtatevikg1michield
authored
ISSUE-338: saml login (#1064)
* update action version * ISSUE-338: login-logout * ISSUE-338: style * ISSUE-338: after review 1 * update SSO login logic * ISSUE-339: oidc login * ISSUE-338: settings --------- Co-authored-by: Tatevik <[email protected]> * ISSUE-338: make login display safe + test config update * ISSUE-338: test * ISSUE-338: show default login --------- Co-authored-by: Tatevik <[email protected]> Co-authored-by: Michiel Dethmers <[email protected]>
1 parent cf72637 commit d1a5c13

File tree

14 files changed

+136
-47
lines changed

14 files changed

+136
-47
lines changed

.github/workflows/main.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ jobs:
1818
experimental: true
1919

2020
steps:
21-
- uses: actions/checkout@v3
21+
- uses: actions/checkout@v4
2222

2323
- name: Set up PHP ${{ matrix.php-version }}
2424
uses: shivammathur/setup-php@v2
@@ -79,8 +79,9 @@ jobs:
7979
cp -fv tests/ci/config.php public_html/lists/config/config.php
8080
mkdir -p output/screenshots
8181
mkdir -p build/mails
82+
chmod -R 777 output/screenshots build/mails
8283
./bin/start-selenium > output/selenium.log 2>&1 &
83-
sleep 5
84+
sleep 15
8485
sudo php -S 0.0.0.0:80 -t public_html > /dev/null 2>&1 &
8586
continue-on-error: ${{ matrix.experimental }}
8687

public_html/lists/admin/home.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,20 @@
130130
</p>
131131

132132
<p><span class="total"><?php echo number_format($lastcampaign['total']) ?></span> Messages sent on <span class="total"><?php echo $lastcampaign['sent'] ?></span>.</p>
133-
<p><span class="total"><?php echo number_format($lastcampaign['views']) ?> </span> Viewed (<span class="total"><?php echo sprintf('%0.2f', ($lastcampaign['views'] / ($lastcampaign['total'] - $lastcampaign['bounced']) * 100)) ?>%</span>), and <span class="total"><?php echo $lastcampaign['bounced'] ?></span> bounced (<span class="total"><?php echo sprintf('%0.2f', ($lastcampaign['bounced'] / $lastcampaign['total'] * 100)) ?>%</span>).</p>
134-
133+
<p>
134+
<span class="total"><?php echo number_format($lastcampaign['views']) ?> </span> Viewed
135+
(<?php
136+
echo $lastcampaign['total'] > 0
137+
? '<span class="total">' . sprintf('%0.2f', ($lastcampaign['views'] / ($lastcampaign['total'] - $lastcampaign['bounced']) * 100)) . '%</span>'
138+
: 'N/A';
139+
?>),
140+
and <span class="total"><?php echo $lastcampaign['bounced'] ?></span> bounced
141+
(<?php
142+
echo $lastcampaign['total'] > 0
143+
? '<span class="total">' . sprintf('%0.2f', ($lastcampaign['bounced'] / $lastcampaign['total'] * 100)) . '%</span>'
144+
: 'N/A';
145+
?>).
146+
</p>
135147
<?php
136148
} ?>
137149

public_html/lists/admin/index.php

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ function mb_strtolower($string)
100100
if (file_exists(dirname(__FILE__).'/../texts/'.$GLOBALS['language_module'])) {
101101
include_once dirname(__FILE__).'/../texts/'.$GLOBALS['language_module'];
102102
}
103+
@session_start();
103104
include_once dirname(__FILE__).'/languages.php';
104105
require_once dirname(__FILE__).'/defaultconfig.php';
105106

@@ -290,6 +291,11 @@ function mb_strtolower($string)
290291
}
291292
echo "$page_title</title>";
292293
$inRemoteCall = false;
294+
if ($page_title === 'enablelogin') {
295+
SaveConfig('hide_default_login', 0);
296+
header('Location: ?page=home');
297+
exit;
298+
}
293299
$doLoginCheck = Sql_Table_exists($tables['admin_login']);
294300

295301
if (!empty($GLOBALS['require_login'])) {
@@ -374,6 +380,9 @@ function mb_strtolower($string)
374380
//$msg = 'Not logged in';
375381
$logged = false;
376382
foreach ($GLOBALS['plugins'] as $pluginname => $plugin) {
383+
if ($pluginname == 'simplesaml' && !isset($_GET[$GLOBALS['plugins'][$pluginname]->autUrl])) {
384+
continue;
385+
}
377386
if ($plugin->login()) {
378387
$logged = true;
379388
break;

public_html/lists/admin/init.php

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -647,7 +647,11 @@
647647
if (!isset($allowed_referrers) || !is_array($allowed_referrers)) {
648648
$allowed_referrers = array();
649649
}
650-
if (isset($_SERVER['HTTP_ORIGIN']) && defined('ACCESS_CONTROL_ALLOW_ORIGINS') && in_array($_SERVER['HTTP_ORIGIN'], ACCESS_CONTROL_ALLOW_ORIGINS)) {
650+
if (
651+
isset($_SERVER['HTTP_ORIGIN'])
652+
&& defined('ACCESS_CONTROL_ALLOW_ORIGINS')
653+
&& in_array($_SERVER['HTTP_ORIGIN'], ACCESS_CONTROL_ALLOW_ORIGINS)
654+
) {
651655
define('ACCESS_CONTROL_ALLOW_ORIGIN', $_SERVER['HTTP_ORIGIN']);
652656
} elseif (!defined('ACCESS_CONTROL_ALLOW_ORIGIN')) {
653657
define('ACCESS_CONTROL_ALLOW_ORIGIN', $GLOBALS['scheme'].'://'.$_SERVER['HTTP_HOST']);

public_html/lists/admin/languages.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,6 @@ function lanSort($a, $b)
5353
if (!empty($GLOBALS['SessionTableName'])) {
5454
require_once dirname(__FILE__).'/sessionlib.php';
5555
}
56-
@session_start();
5756

5857
if (isset($_POST['setlanguage']) && !empty($_POST['setlanguage']) && is_array($LANGUAGES[$_POST['setlanguage']])) {
5958
//# just in case

public_html/lists/admin/login.php

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,41 @@ function footer()
4646
echo '</div></form>';
4747
}
4848

49+
function enableDefaultLogin()
50+
{
51+
echo '<div class="login"><p>';
52+
echo '<strong>' . $GLOBALS['I18N']->get('Having trouble with SSO login?') . '</strong><br>';
53+
echo $GLOBALS['I18N']->get('You can still use default login by clicking on the button') . ' ';
54+
echo '<a href="?page=enablelogin" class="submit">' . $GLOBALS['I18N']->get('Enable default login') . '</a>';
55+
echo '</p><div class="clear"></div></div>';
56+
}
57+
58+
59+
function renderSSO()
60+
{
61+
if (!empty($GLOBALS['ssoplugin'])) {
62+
echo '<form method="post" id="forgotpassword-form" action="">';
63+
echo '<div style="display: flex; justify-content: space-around; align-items: center;">';
64+
65+
foreach ($GLOBALS['ssoplugin'] as $plugin) {
66+
if (isset($GLOBALS['plugins'][$plugin])) {
67+
$pluginInstance = $GLOBALS['plugins'][$plugin];
68+
$ssoUrl = $pluginInstance->autUrl;
69+
$buttonText = 'Login with ' . getConfig($pluginInstance->name);
70+
71+
echo '<a href="?' . $ssoUrl . '"
72+
style="display: inline-block; padding: 8px 15px; background-color: #3c3c3c; color: #fff;
73+
text-decoration: none; border-radius: 5px; font-size: 16px; text-align: center;
74+
min-width: 120px;">
75+
' . $buttonText . '
76+
</a>';
77+
}
78+
}
79+
80+
echo '</div>';
81+
echo '</form>';
82+
}
83+
}
4984
//Delete from the DB every token older than certain elapsed time.
5085
function deleteOldTokens()
5186
{
@@ -116,16 +151,24 @@ function deleteOldTokens()
116151
exit;
117152
}
118153
} else {
119-
echo "<form method=\"post\" id=\"login-form\" action=\"\">\n";
120-
echo " <input type=\"hidden\" name=\"page\" value=\"$page\" />\n";
121-
echo " <table class=\"loginPassUpdate\" width=\"100%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\">\n";
122-
echo ' <tr><td><span class="general">'.$GLOBALS['I18N']->get('Name').":</span></td></tr>\n";
123-
echo ' <tr><td><input type="text" name="login" value="" size="30" autofocus="autofocus" /></td></tr>';
124-
echo ' <tr><td><span class="general">'.$GLOBALS['I18N']->get('Password').':</span></td></tr>';
125-
echo ' <tr><td><input type="password" name="password" value="" size="30" /></td></tr>';
126-
echo ' <tr><td><input class="submit" type="submit" name="process" value="'.$GLOBALS['I18N']->get('Continue').'" /></td></tr>';
127-
echo ' </table>';
128-
echo '</form>';
129-
footer();
154+
$showDefaultLogin = !isset($GLOBALS['ssoplugin']) || !getConfig('hide_default_login');
155+
if ($showDefaultLogin) {
156+
echo "<form method=\"post\" id=\"login-form\" action=\"\">\n";
157+
echo " <input type=\"hidden\" name=\"page\" value=\"$page\" />\n";
158+
echo " <table class=\"loginPassUpdate\" width=\"100%\" border=\"0\" cellpadding=\"2\" cellspacing=\"0\">\n";
159+
echo ' <tr><td><span class="general">'.$GLOBALS['I18N']->get('Name').":</span></td></tr>\n";
160+
echo ' <tr><td><input type="text" name="login" value="" size="30" autofocus="autofocus" /></td></tr>';
161+
echo ' <tr><td><span class="general">'.$GLOBALS['I18N']->get('Password').':</span></td></tr>';
162+
echo ' <tr><td><input type="password" name="password" value="" size="30" /></td></tr>';
163+
echo ' <tr><td><input class="submit" type="submit" name="process" value="'.$GLOBALS['I18N']->get('Continue').'" /></td></tr>';
164+
echo ' </table>';
165+
echo '</form>';
166+
footer();
167+
}
168+
renderSSO();
169+
170+
if (!$showDefaultLogin) {
171+
enableDefaultLogin();
172+
}
130173
}
131174
?>

public_html/lists/admin/pluginlib.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
$GLOBALS['emailsenderplugin'] = false;
1313
$GLOBALS['analyticsqueryplugin'] = false;
1414
$GLOBALS['updaterplugin'] = false;
15+
$GLOBALS['ssoplugin'] = [];
1516

1617
$pluginRootDirs = array();
1718
if (PLUGIN_ROOTDIRS != '') {
@@ -111,6 +112,10 @@
111112
) {
112113
$GLOBALS['editorplugin'] = $className;
113114
}
115+
if (method_exists($pluginInstance, 'login') && isset($pluginInstance->ssoProvider))
116+
{
117+
$GLOBALS['ssoplugin'][] = $className;
118+
}
114119
if (!$GLOBALS['authenticationplugin'] && $pluginInstance->authProvider && method_exists($pluginInstance,
115120
'validateLogin')
116121
) {

public_html/lists/admin/plugins/.htaccess

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
Require all denied
1111
</IfModule>
1212
</FilesMatch>
13-
<FilesMatch "index.php$">
13+
<FilesMatch "(index.php|module.php)$">
1414
# Apache < 2.3
1515
<IfModule !mod_authz_core.c>
1616
Order allow,deny

tests/ci/behat.yml

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,11 @@ default:
77
- ./features
88
contexts:
99
- FeatureContext:
10-
# Set database access credentials
1110
database:
1211
host: 127.0.0.1
1312
user: phplist
1413
password: phplist
1514
name: phplistdb
16-
# Set admin user login credentials
1715
admin:
1816
username: admin
1917
password: Mypassword123+
@@ -24,7 +22,7 @@ default:
2422
- FailAid\Context\FailureContext
2523
extensions:
2624
Behat\MinkExtension:
27-
show_cmd: 'cp %s ./output/lastResponse.html' #'cat %s'
25+
show_cmd: 'cp %s ./output/lastResponse.html'
2826
base_url: 'http://127.0.0.1'
2927
default_session: chrome
3028
sessions:
@@ -35,6 +33,11 @@ default:
3533
browserName: chrome
3634
browser: chrome
3735
version: ""
36+
extra_capabilities:
37+
timeouts:
38+
implicit: 10000 # 5 seconds for implicit waits
39+
pageLoad: 60000 # 30 seconds for page loads
40+
script: 60000 # 30 seconds for async scripts
3841
chrome:
3942
switches:
4043
- "--headless"
@@ -54,7 +57,7 @@ default:
5457
selenium2:
5558
browser: "firefox"
5659
wd_host: http://127.0.0.1:4444/wd/hub
57-
FailAid\Extension:
60+
FailAid\Extension:
5861
screenshot:
5962
directory: /tmp/screenshots/
6063
mode: default

tests/features/bootstrap/FeatureContext.php

Lines changed: 26 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,8 @@
11
<?php
22

3-
use Behat\Behat\Context\Context;
43

54
use Behat\Mink\Exception\ExpectationException;
65
use Behat\MinkExtension\Context\MinkContext;
7-
#use Behat\MinkExtension\Context\RawMinkContext;
8-
9-
//
10-
// Require 3rd-party libraries here:
11-
//
12-
// require_once 'PHPUnit/Autoload.php';
13-
// require_once 'PHPUnit/Framework/Assert/Functions.php';
14-
//
156

167
/**
178
* Features context.
@@ -107,7 +98,7 @@ public function spins($closure, $tries = 10)
10798
$closure();
10899

109100
return;
110-
} catch (\Exception $e) {
101+
} catch (Exception $e) {
111102
if ($i == $tries) {
112103
throw $e;
113104
}
@@ -185,7 +176,7 @@ public function isLoggedIn($throwsException = false)
185176
{
186177
$retVal = $this->token != null;
187178
if(!$retVal && $throwsException){
188-
throw new \Exception('Not logged in yet');
179+
throw new Exception('Not logged in yet');
189180
}
190181
return $retVal;
191182
}
@@ -339,4 +330,28 @@ public function iConfirmThePopup()
339330
$this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
340331
}
341332

333+
/**
334+
* @Then I must see :text
335+
*/
336+
public function iMustSee($text)
337+
{
338+
$maxAttempts = 3;
339+
$waitTimeMs = 1000;
340+
$this->getSession()->wait(5000, "document.readyState === 'complete'");
341+
342+
for ($attempt = 1; $attempt <= $maxAttempts; $attempt++) {
343+
try {
344+
$this->assertSession()->pageTextContains($this->fixStepArgument($text));
345+
return;
346+
} catch (\WebDriver\Exception\StaleElementReference $e) {
347+
// Handle Selenium stale element exception, retry
348+
} catch (\Behat\Mink\Exception\ResponseTextException $e) {
349+
// Handle Mink text assertion failure, retry
350+
}
351+
352+
usleep($waitTimeMs * 1000);
353+
}
354+
355+
throw new Exception(sprintf("Text '%s' not found after %d attempts.", $text, $maxAttempts));
356+
}
342357
}

0 commit comments

Comments
 (0)