dolibarr  20.0.0-beta
functions_openid_connect.php
Go to the documentation of this file.
1 <?php
2 /* Copyright (C) 2022 Jeritiana Ravelojaona <jeritiana.rav@smartone.ai>
3  * Copyright (C) 2024 MDW <mdeweerd@users.noreply.github.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program. If not, see <https://www.gnu.org/licenses/>.
17  */
18 
27 include_once DOL_DOCUMENT_ROOT.'/core/lib/geturl.lib.php';
28 
38 function check_user_password_openid_connect($usertotest, $passwordtotest, $entitytotest)
39 {
40  global $db, $conf, $langs;
41 
42  // Force master entity in transversal mode
43  $entity = $entitytotest;
44  if (isModEnabled('multicompany') && getDolGlobalString('MULTICOMPANY_TRANSVERSE_MODE')) {
45  $entity = 1;
46  }
47 
48  $login = '';
49 
50  dol_syslog("functions_openid_connect::check_user_password_openid_connect usertotest=".$usertotest." passwordtotest=".preg_replace('/./', '*', $passwordtotest)." entitytotest=".$entitytotest);
51 
52  // Step 1 is done by user: request an authorization code
53 
54  if (GETPOSTISSET('username')) {
55  // OIDC does not require credentials here: pass on to next auth handler
56  $_SESSION["dol_loginmesg"] = "Not an OpenID Connect flow";
57  dol_syslog("functions_openid_connect::check_user_password_openid_connect not an OIDC flow");
58  } elseif (GETPOSTISSET('code')) {
59  $auth_code = GETPOST('code', 'aZ09');
60  dol_syslog("functions_openid_connect::check_user_password_openid_connect code=".$auth_code);
61 
62  // Step 2: turn the authorization code into an access token, using client_secret
63  $auth_param = [
64  'grant_type' => 'authorization_code',
65  'client_id' => getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLIENT_ID'),
66  'client_secret' => getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLIENT_SECRET'),
67  'code' => $auth_code,
68  'redirect_uri' => getDolGlobalString('MAIN_AUTHENTICATION_OIDC_REDIRECT_URL')
69  ];
70 
71  $token_response = getURLContent($conf->global->MAIN_AUTHENTICATION_OIDC_TOKEN_URL, 'POST', http_build_query($auth_param));
72  $token_content = json_decode($token_response['content']);
73  dol_syslog("functions_openid_connect::check_user_password_openid_connect /token=".print_r($token_response, true), LOG_DEBUG);
74 
75  if (property_exists($token_content, 'access_token')) {
76  // Step 3: retrieve user info using token
77  $userinfo_headers = array('Authorization: Bearer '.$token_content->access_token);
78  $userinfo_response = getURLContent($conf->global->MAIN_AUTHENTICATION_OIDC_USERINFO_URL, 'GET', '', 1, $userinfo_headers);
79  $userinfo_content = json_decode($userinfo_response['content']);
80 
81  dol_syslog("functions_openid_connect::check_user_password_openid_connect /userinfo=".print_r($userinfo_response, true), LOG_DEBUG);
82 
83  // Get the user attribute (claim) matching the Dolibarr login
84  $login_claim = 'email'; // default
85  if (getDolGlobalString('MAIN_AUTHENTICATION_OIDC_LOGIN_CLAIM')) {
86  $login_claim = getDolGlobalString('MAIN_AUTHENTICATION_OIDC_LOGIN_CLAIM');
87  }
88 
89  if (property_exists($userinfo_content, $login_claim)) {
90  // Success: retrieve claim to return to Dolibarr as login
91  $sql = 'SELECT login, entity, datestartvalidity, dateendvalidity';
92  $sql .= ' FROM '.MAIN_DB_PREFIX.'user';
93  $sql .= " WHERE login = '".$db->escape($userinfo_content->$login_claim)."'";
94  $sql .= ' AND entity IN (0,'.(array_key_exists('dol_entity', $_SESSION) ? ((int) $_SESSION["dol_entity"]) : 1).')';
95 
96  dol_syslog("functions_openid::check_user_password_openid", LOG_DEBUG);
97 
98  $resql = $db->query($sql);
99  if ($resql) {
100  $obj = $db->fetch_object($resql);
101  if ($obj) {
102  // Note: Test on date validity is done later natively with isNotIntoValidityDateRange() by core after calling checkLoginPassEntity() that call this method
103  $login = $obj->login;
104  }
105  }
106  } elseif ($userinfo_content->error) {
107  // Got user info response but content is an error
108  $_SESSION["dol_loginmesg"] = "Error in OAuth 2.0 flow (".$userinfo_content->error_description.")";
109  } elseif ($userinfo_response['http_code'] == 200) {
110  // Claim does not exist
111  $_SESSION["dol_loginmesg"] = "OpenID Connect claim not found: ".$login_claim;
112  } elseif ($userinfo_response['curl_error_no']) {
113  // User info request error
114  $_SESSION["dol_loginmesg"] = "Network error: ".$userinfo_response['curl_error_msg']." (".$userinfo_response['curl_error_no'].")";
115  } else {
116  // Other user info request error
117  $_SESSION["dol_loginmesg"] = "Userinfo request error (".$userinfo_response['http_code'].")";
118  }
119  } elseif ($token_content->error) {
120  // Got token response but content is an error
121  $_SESSION["dol_loginmesg"] = "Error in OAuth 2.0 flow (".$token_content->error_description.")";
122  } elseif ($token_response['curl_error_no']) {
123  // Token request error
124  $_SESSION["dol_loginmesg"] = "Network error: ".$token_response['curl_error_msg']." (".$token_response['curl_error_no'].")";
125  } else {
126  // Other token request error
127  $_SESSION["dol_loginmesg"] = "Token request error (".$token_response['http_code'].")";
128  }
129  } else {
130  // No code received
131  $_SESSION["dol_loginmesg"] = "Error in OAuth 2.0 flow (no code received)";
132  }
133 
134  dol_syslog("functions_openid_connect::check_user_password_openid_connect END");
135 
136  return !empty($login) ? $login : false;
137 }
if(isModEnabled('invoice') && $user->hasRight('facture', 'lire')) if((isModEnabled('fournisseur') &&!getDolGlobalString('MAIN_USE_NEW_SUPPLIERMOD') && $user->hasRight("fournisseur", "facture", "lire"))||(isModEnabled('supplier_invoice') && $user->hasRight("supplier_invoice", "lire"))) if(isModEnabled('don') && $user->hasRight('don', 'lire')) if(isModEnabled('tax') && $user->hasRight('tax', 'charges', 'lire')) if(isModEnabled('invoice') &&isModEnabled('order') && $user->hasRight("commande", "lire") &&!getDolGlobalString('WORKFLOW_DISABLE_CREATE_INVOICE_FROM_ORDER')) $sql
Social contributions to pay.
Definition: index.php:745
GETPOST($paramname, $check='alphanohtml', $method=0, $filter=null, $options=null, $noreplace=0)
Return value of a param into GET or POST supervariable.
GETPOSTISSET($paramname)
Return true if we are in a context of submitting the parameter $paramname from a POST of a form.
getDolGlobalString($key, $default='')
Return dolibarr global constant string value.
isModEnabled($module)
Is Dolibarr module enabled.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
check_user_password_openid_connect($usertotest, $passwordtotest, $entitytotest)
Check validity of user/password/entity If test is ko, reason must be filled into $_SESSION["dol_login...
getURLContent($url, $postorget='GET', $param='', $followlocation=1, $addheaders=array(), $allowedschemes=array('http', 'https'), $localurl=0, $ssl_verifypeer=-1)
Function to get a content from an URL (use proxy if proxy defined).
Definition: geturl.lib.php:42