dolibarr 24.0.0-beta
openid_connect.lib.php
Go to the documentation of this file.
1<?php
2/* Copyright (C) 2017 Open-DSI <support@open-dsi.fr>
3 * Copyright (C) 2024-2026 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 <http://www.gnu.org/licenses/>.
17 */
18
25require_once DOL_DOCUMENT_ROOT.'/user/class/user.class.php';
26require_once DOL_DOCUMENT_ROOT.'/core/lib/security2.lib.php';
27
28
40{
41 global $dolibarr_main_instance_unique_id;
42
43 $nonce = bin2hex(random_bytes(16));
44 $signature = hash_hmac('sha256', $nonce, $dolibarr_main_instance_unique_id);
45
46 return $nonce.'.'.$signature;
47}
48
59{
60 global $dolibarr_main_instance_unique_id;
61
62 if (empty($state)) {
63 return false;
64 }
65
66 $parts = explode('.', $state, 2);
67 if (count($parts) !== 2) {
68 return false;
69 }
70
71 $nonce = $parts[0];
72 $signature = $parts[1];
73
74 $expected = hash_hmac('sha256', $nonce, $dolibarr_main_instance_unique_id);
75
76 return hash_equals($expected, $signature);
77}
78
79
86{
87 return DOL_MAIN_URL_ROOT . '/core/modules/openid_connect/callback.php';
88}
89
90
97{
98 // Note: For the scope, we must use rawurlencode instead of urlencode.
99 $url = getDolGlobalString('MAIN_AUTHENTICATION_OIDC_AUTHORIZE_URL').'?client_id='.urlencode(getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLIENT_ID')).'&redirect_uri='.urlencode(openid_connect_get_redirect_url()).'&scope='.rawurlencode(getDolGlobalString('MAIN_AUTHENTICATION_OIDC_SCOPES')).'&response_type=code&state='.urlencode(openid_connect_get_state());
100
101 return $url;
102}
103
104
118function openid_connect_create_user($db, $userinfo, $login, $entity)
119{
120 // Read claim mapping configuration
121 $claim_email = getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLAIM_EMAIL', 'email');
122 $claim_firstname = getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLAIM_FIRSTNAME', 'given_name');
123 $claim_lastname = getDolGlobalString('MAIN_AUTHENTICATION_OIDC_CLAIM_LASTNAME', 'family_name');
124
125 // Sanitize login using Dolibarr forbidden characters for logins.
127 $sanitized_login = $login;
128
129 if ($badChars !== '' && preg_match('/['.preg_quote($badChars, '/').']/', $login)) {
130 // First try preferred_username from OIDC (common standard claim)
131 if (property_exists($userinfo, 'preferred_username') && !empty($userinfo->preferred_username)) {
132 $preferred = $userinfo->preferred_username;
133 if (!preg_match('/['.preg_quote($badChars, '/').']/', $preferred)) {
134 $sanitized_login = $preferred;
135 }
136 }
137 // If still invalid (no preferred_username or it also has bad chars), extract local part of email
138 if (preg_match('/['.preg_quote($badChars, '/').']/', $sanitized_login) && strpos($sanitized_login, '@') !== false) {
139 $sanitized_login = substr($sanitized_login, 0, strpos($sanitized_login, '@'));
140 }
141 // Final fallback: replace any remaining bad characters
142 $sanitized_login = (string) preg_replace('/['.preg_quote($badChars, '/').']/', '.', $sanitized_login);
143 }
144
145 $newuser = new User($db);
146 $newuser->login = $sanitized_login;
147 $newuser->entity = $entity;
148 $newuser->statut = 1; // Active
149 $newuser->status = 1; // Active (alias)
150
151 if (property_exists($userinfo, $claim_email)) {
152 $newuser->email = $userinfo->$claim_email;
153 }
154 if (property_exists($userinfo, $claim_firstname)) {
155 $newuser->firstname = $userinfo->$claim_firstname;
156 }
157 if (property_exists($userinfo, $claim_lastname)) {
158 $newuser->lastname = $userinfo->$claim_lastname;
159 }
160 // If no lastname from claims, use login as fallback (lastname is required)
161 if (empty($newuser->lastname)) {
162 $newuser->lastname = $login;
163 }
164
165 // Set a random password (user authenticates via OIDC, not locally)
166 $newuser->pass = getRandomPassword(true);
167
168 // Find the admin user to set as creator (configurable, default: user ID 1)
169 $creator_id = getDolGlobalInt('MAIN_AUTHENTICATION_OIDC_DEFAULT_CREATOR', 1);
170 if ($creator_id <= 0) {
171 $creator_id = 1;
172 }
173 $adminuser = new User($db);
174 $result_fetch = $adminuser->fetch($creator_id);
175 if ($result_fetch <= 0 || empty($adminuser->admin) || $adminuser->statut != 1) {
176 dol_syslog("openid_connect_create_user::Error: configured creator user ID=".$creator_id." is not a valid active admin", LOG_ERR);
177 return -2;
178 }
179
180 $db->begin();
181
182 $result_create = $newuser->create($adminuser);
183 if ($result_create < 0) {
184 $db->rollback();
185 dol_syslog("openid_connect_create_user::Error creating user: ".$newuser->error, LOG_ERR);
186 return $result_create;
187 }
188
189 // Add to default group if configured
190 $default_group = getDolGlobalInt('MAIN_AUTHENTICATION_OIDC_DEFAULT_GROUP');
191 if ($default_group > 0) {
192 $res_group = $newuser->SetInGroup($default_group, $entity);
193 if ($res_group < 0) {
194 dol_syslog("openid_connect_create_user::Warning: Error adding user to group ".$default_group.": ".$newuser->error, LOG_WARNING);
195 // Don't fail user creation if group assignment fails
196 }
197 }
198
199 $db->commit();
200
201 dol_syslog("openid_connect_create_user::User created id=".$result_create." login=".$sanitized_login);
202
203 return $sanitized_login;
204}
Class to manage Dolibarr users.
if(!isModEnabled('ai')||!getDolGlobalString('AI_ASSISTANT_ENABLED')) global $db
API class for accounts.
getDolGlobalLoginBadCharUnauthorized()
Return the list of unauthorized characters in user logins.
getDolGlobalInt($key, $default=0)
Return a Dolibarr global constant int value.
getDolGlobalString($key, $default='')
Return a Dolibarr global constant string value.
dol_syslog($message, $level=LOG_INFO, $ident=0, $suffixinfilename='', $restricttologhandler='', $logcontext=null)
Write log message into outputs.
print $langs trans("Show") . '< td style="' . $timeColor . '" align="center"> s</td > badge status0 badge status4 badge status3 Error badge status8< td align="center">< span class="badge ' . $badge . '"></span ></td >< td align="center">< a href="#" class="button button-small" onclick="openLogModal(this)" data-req="' . dol_escape_htmltag($reqSafe) . '" data-res="' . dol_escape_htmltag($resSafe) . '" data-err="' . dol_escape_htmltag($errSafe) . '">< span class="fa fa-search-plus"></span ></a ></td ></tr >< tr >< td colspan="' . $colspan . '" class="opacitymedium"></td ></tr ></table ></div ></form > logModal none logModal none s a JSON string
buildzip.php
openid_connect_verify_state($state)
Verify an OIDC state token.
openid_connect_get_url()
Return the OIDC authorization URL.
openid_connect_create_user($db, $userinfo, $login, $entity)
Create a Dolibarr user from OIDC userinfo claims.
openid_connect_get_state()
Generate a self-verifiable state token for the OIDC authorization request.
openid_connect_get_redirect_url()
Return the OIDC callback redirect URL.
getRandomPassword($generic=false, $replaceambiguouschars=null, $length=32)
Return a generated password using default module.