Merge pull request #22235 from kurund/contribution-import
[civicrm-core.git] / ext / authx / authx.php
1 <?php
2
3 require_once 'authx.civix.php';
4 // phpcs:disable
5 use CRM_Authx_ExtensionUtil as E;
6 // phpcs:enable
7
8 Civi::dispatcher()->addListener('civi.invoke.auth', function($e) {
9 $params = ($_SERVER['REQUEST_METHOD'] === 'GET') ? $_GET : $_POST;
10 $siteKey = $_SERVER['HTTP_X_CIVI_KEY'] ?? $params['_authxSiteKey'] ?? NULL;
11
12 if (!empty($_SERVER['HTTP_X_CIVI_AUTH'])) {
13 return (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'xheader', 'cred' => $_SERVER['HTTP_X_CIVI_AUTH'], 'siteKey' => $siteKey]);
14 }
15
16 if (!empty($_SERVER['HTTP_AUTHORIZATION'])) {
17 return (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'header', 'cred' => $_SERVER['HTTP_AUTHORIZATION'], 'siteKey' => $siteKey]);
18 }
19
20 if (!empty($params['_authx'])) {
21 if ((implode('/', $e->args) === 'civicrm/authx/login')) {
22 (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'login', 'cred' => $params['_authx'], 'useSession' => TRUE, 'siteKey' => $siteKey]);
23 _authx_redact(['_authx']);
24 }
25 elseif (!empty($params['_authxSes'])) {
26 (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'auto', 'cred' => $params['_authx'], 'useSession' => TRUE, 'siteKey' => $siteKey]);
27 if ($_SERVER['REQUEST_METHOD'] === 'GET') {
28 _authx_reload(implode('/', $e->args), $_SERVER['QUERY_STRING']);
29 }
30 else {
31 _authx_redact(['_authx', '_authxSes']);
32 }
33 }
34 else {
35 (new \Civi\Authx\Authenticator())->auth($e, ['flow' => 'param', 'cred' => $params['_authx'], 'siteKey' => $siteKey]);
36 _authx_redact(['_authx']);
37 }
38 }
39 });
40
41 /**
42 * Perform a system login.
43 *
44 * This is useful for backend scripts that need to switch to a specific user.
45 *
46 * As needed, this will update the Civi session and CMS data.
47 *
48 * @param array{flow: ?string, useSession: ?bool, principal: ?array, cred: ?string,} $details
49 * Describe the authentication process with these properties:
50 *
51 * - string $flow (default 'script');
52 * The type of authentication flow being used
53 * Ex: 'param', 'header', 'auto'
54 * - bool $useSession (default FALSE)
55 * If TRUE, then the authentication should be persistent (in a session variable).
56 * If FALSE, then the authentication should be ephemeral (single page-request).
57 *
58 * And then ONE of these properties to describe the user/principal:
59 *
60 * - string $cred
61 * The credential, as formatted in the 'Authorization' header.
62 * Ex: 'Bearer 12345', 'Basic ASDFFDSA=='
63 * - array $principal
64 * Description of a validated principal.
65 * Must include 'contactId', 'userId', xor 'user'
66 * @return array{contactId: int, userId: ?int, flow: string, credType: string, useSession: bool}
67 * An array describing the authenticated session.
68 * @throws \Civi\Authx\AuthxException
69 */
70 function authx_login(array $details): array {
71 $defaults = ['flow' => 'script', 'useSession' => FALSE];
72 $details = array_merge($defaults, $details);
73 $auth = new \Civi\Authx\Authenticator();
74 $auth->setRejectMode('exception');
75 $auth->auth(NULL, array_merge($defaults, $details));
76 return \CRM_Core_Session::singleton()->get("authx");
77 }
78
79 /**
80 * @return \Civi\Authx\AuthxInterface
81 */
82 function _authx_uf() {
83 $class = 'Civi\\Authx\\' . CIVICRM_UF;
84 return class_exists($class) ? new $class() : new \Civi\Authx\None();
85 }
86
87 /**
88 * For parameter-based authentication, this option will hide parameters.
89 * This is mostly a precaution, hedging against the possibility that some routes
90 * make broad use of $_GET or $_PARAMS.
91 *
92 * @param array $keys
93 */
94 function _authx_redact(array $keys) {
95 foreach ($keys as $key) {
96 unset($_POST[$key], $_GET[$key], $_REQUEST[$key]);
97 }
98 }
99
100 /**
101 * Reload the current page-view.
102 *
103 * @param string $route
104 * @param string $queryString
105 */
106 function _authx_reload($route, $queryString) {
107 parse_str($queryString, $query);
108 foreach (array_keys($query) as $key) {
109 if (CRM_Utils_String::startsWith($key, '_authx')) {
110 unset($query[$key]);
111 }
112 }
113 $url = CRM_Utils_System::url($route, $query, TRUE, NULL, FALSE, CRM_Core_Config::singleton()->userSystem->isFrontEndPage());
114 CRM_Utils_System::redirect($url);
115 }
116
117 /**
118 * Implements hook_civicrm_config().
119 *
120 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_config/
121 */
122 function authx_civicrm_config(&$config) {
123 _authx_civix_civicrm_config($config);
124 }
125
126 /**
127 * Implements hook_civicrm_install().
128 *
129 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_install
130 */
131 function authx_civicrm_install() {
132 _authx_civix_civicrm_install();
133 }
134
135 /**
136 * Implements hook_civicrm_postInstall().
137 *
138 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_postInstall
139 */
140 function authx_civicrm_postInstall() {
141 _authx_civix_civicrm_postInstall();
142 }
143
144 /**
145 * Implements hook_civicrm_uninstall().
146 *
147 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_uninstall
148 */
149 function authx_civicrm_uninstall() {
150 _authx_civix_civicrm_uninstall();
151 }
152
153 /**
154 * Implements hook_civicrm_enable().
155 *
156 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_enable
157 */
158 function authx_civicrm_enable() {
159 _authx_civix_civicrm_enable();
160 }
161
162 /**
163 * Implements hook_civicrm_disable().
164 *
165 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_disable
166 */
167 function authx_civicrm_disable() {
168 _authx_civix_civicrm_disable();
169 }
170
171 /**
172 * Implements hook_civicrm_upgrade().
173 *
174 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_upgrade
175 */
176 function authx_civicrm_upgrade($op, CRM_Queue_Queue $queue = NULL) {
177 return _authx_civix_civicrm_upgrade($op, $queue);
178 }
179
180 /**
181 * Implements hook_civicrm_entityTypes().
182 *
183 * Declare entity types provided by this module.
184 *
185 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_entityTypes
186 */
187 function authx_civicrm_entityTypes(&$entityTypes) {
188 _authx_civix_civicrm_entityTypes($entityTypes);
189 }
190
191 /**
192 * Implements hook_civicrm_permission().
193 *
194 * @see CRM_Utils_Hook::permission()
195 */
196 function authx_civicrm_permission(&$permissions) {
197 $permissions['authenticate with password'] = E::ts('AuthX: Authenticate to services with password');
198 $permissions['authenticate with api key'] = E::ts('AuthX: Authenticate to services with API key');
199 }
200
201 // --- Functions below this ship commented out. Uncomment as required. ---
202
203 /**
204 * Implements hook_civicrm_preProcess().
205 *
206 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_preProcess
207 */
208 //function authx_civicrm_preProcess($formName, &$form) {
209 //
210 //}
211
212 /**
213 * Implements hook_civicrm_navigationMenu().
214 *
215 * @link https://docs.civicrm.org/dev/en/latest/hooks/hook_civicrm_navigationMenu
216 */
217 //function authx_civicrm_navigationMenu(&$menu) {
218 // _authx_civix_insert_navigation_menu($menu, 'Mailings', array(
219 // 'label' => E::ts('New subliminal message'),
220 // 'name' => 'mailing_subliminal_message',
221 // 'url' => 'civicrm/mailing/subliminal',
222 // 'permission' => 'access CiviMail',
223 // 'operator' => 'OR',
224 // 'separator' => 0,
225 // ));
226 // _authx_civix_navigationMenu($menu);
227 //}