-
Notifications
You must be signed in to change notification settings - Fork 1
/
Sso.php
129 lines (106 loc) · 3.95 KB
/
Sso.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
<?php declare(strict_types=1);
namespace Module\Support\Webapps\App\Type\Wordpress;
class Sso
{
use \ContextableTrait;
use \apnscpFunctionInterceptorTrait;
const PACKAGE_NAME = 'aaemnnosttv/wp-cli-login-command';
protected Handler $app;
protected function __construct(Handler $app)
{
$this->app = $app;
}
public function handle(): bool
{
$admin = $this->app->wordpress_get_admin($this->app->getHostname(), $this->app->getPath());
if (!$admin) {
return error("SSO failed. Cannot lookup admin");
}
$ret = Wpcli::instantiateContexted($this->getAuthContext())
->exec($this->app->getAppRoot(), '--skip-themes login create --url-only %s', [$admin]);
$magic = trim($ret['stdout']);
if (!preg_match(\Regex::URL, $magic)) {
// garbage output, possibly requiring wp-cli-login-command update
// let's try it again
$oldVersion = $this->loginCommandVersion();
$ret = Wpcli::instantiateContexted($this->getAuthContext())->
exec($this->app->getAppRoot(), 'package update %s', [self::PACKAGE_NAME]);
if ($ret['success']) {
info("Updating %s", self::PACKAGE_NAME);
$this->enable();
}
if ($this->loginCommandVersion() === $oldVersion) {
return error("Failed to upgrade %(package)s: %(err)s", [
'package' => self::PACKAGE_NAME, 'err' => coalesce($ret['stderr'], $ret['stdout'])
]);
}
}
if (!$ret['success']) {
return error("SSO failed. Cannot create session: %s", coalesce($ret['stderr'], $ret['stdout']));
}
\Util_HTTP::forwardNoProxy();
$url = $this->discoverRedirectionUrl($magic);
header("Location: " . $url, true, 302);
exit(0);
}
private function loginCommandVersion(): ?string
{
$ret = Wpcli::instantiateContexted($this->getAuthContext())->exec($this->app->getAppRoot(),
'package list --format=json ');
foreach ((array)json_decode($ret['stdout'], true) as $item) {
if ($item['name'] === self::PACKAGE_NAME) {
return $item['version'];
}
};
return null;
}
public function install(): bool
{
return $this->wordpress_install_package(static::PACKAGE_NAME);
}
public function enable(): bool
{
$ret = Wpcli::instantiateContexted($this->getAuthContext())
->exec($this->app->getAppRoot(), '--skip-themes --skip-plugins login install --yes --activate');
return $ret['success'] ?: error("Failed to activate SSO: %s", coalesce($ret['stderr'], $ret['stdout']));
}
/**
* Ascertain redirection URL on rewrite presence
*
* @param string $redirect
* @return string
*/
private function discoverRedirectionUrl(string $redirect): string
{
// WordPress can direct (foo.com) or indirect (foo.com/wp2 -> foo.com)
// Likewise WordPress can be pathless (foo.com) and pathed (foo.com/wp -> foo.com/wp)
// Lastly, WordPress can have a dispatcher/pretty-print URLs or not (foo.com/index.php/)
$parts = parse_url($redirect);
$url = $parts['scheme'] . '://' . $parts['host'];
$pathComponents = explode('/', $parts['path']);
$path = implode('/', array_slice($pathComponents, 0, -2));
// Try parsing the suggested docroot first
$roots = [$this->app->getDocumentRoot()];
if (($testRoot = $this->app->web_get_docroot($parts['host'], $path)) && $testRoot !== current($roots)) {
array_unshift($roots, $testRoot);
}
foreach ($roots as $root) {
$htaccess = $root . '/.htaccess';
if ($this->file_exists($htaccess) && false !== strpos($this->file_get_file_contents($htaccess),
'/index.php')) {
return $url . $parts['path'];
}
// No .htaccess
$loginPathNormalized = ltrim($parts['path'], '/');
$webappPathNormalized = ltrim($this->app->getPath(), '/');
if ($this->file_exists($root . '/wp-config.php')) {
warn("Pretty-print URLs not enabled in WordPress. SSO path likely incorrect");
// strip common path component to insert /index.php dispatcher
return $url . '/' . ltrim($this->app->getPath() . '/index.php',
'/') . '/' . ltrim(substr($loginPathNormalized,
strlen($webappPathNormalized)), '/');
}
}
return $url . $parts['path'];
}
}