70 public $httpcode = 401;
123 if ($server ===
null) {
132 if (!empty($server[
'HTTP_DOLAPIKEY'])) {
133 $credential = $server[
'HTTP_DOLAPIKEY'];
136 if ($credential ===
'') {
138 if (!empty($server[
'HTTP_AUTHORIZATION'])) {
139 $authheader = $server[
'HTTP_AUTHORIZATION'];
140 } elseif (!empty($server[
'REDIRECT_HTTP_AUTHORIZATION'])) {
141 $authheader = $server[
'REDIRECT_HTTP_AUTHORIZATION'];
142 } elseif (function_exists(
'getallheaders')) {
143 $headers = array_change_key_case(getallheaders(), CASE_LOWER);
144 $authheader = isset($headers[
'authorization']) ? $headers[
'authorization'] :
'';
147 if ($authheader !==
'' && preg_match(
'/^Bearer\s+(\S+)$/i', $authheader, $reg)) {
148 $credential = $reg[1];
152 if ($credential ===
'' && !empty($server[
'HTTP_X_API_KEY'])) {
153 $credential = $server[
'HTTP_X_API_KEY'];
162 if ($credential ===
'') {
163 foreach (array(
'DOLAPIKEY',
'api_key',
'key') as $param) {
164 if (!empty($get[$param])) {
165 $credential = $get[$param];
188 $this->httpcode = 401;
195 if ($credential ===
'') {
196 $this->error =
'Missing credentials. Provide a Dolibarr API key with an "Authorization: Bearer <key>" or "DOLAPIKEY: <key>" header.';
203 if (preg_match(
'/^dolcrypt:/i', $credential)) {
204 $this->httpcode = 503;
205 $this->error =
'Bad value for the API key. An API key should not start with dolcrypt:';
212 if ($sharedkey !==
'' && hash_equals($sharedkey, $credential)) {
219 require_once DOL_DOCUMENT_ROOT.
'/user/class/user.class.php';
221 $tmpuser =
new User($this->db);
222 if ($tmpuser->fetch($userid) <= 0) {
223 dol_syslog(
'[MCP Server] Authentication KO: cannot load user '.$userid, LOG_ERR);
224 $this->error =
'Unauthorized';
227 $tmpuser->loadRights();
234 if (!$tmpuser->hasRight(
'ai',
'assistant',
'use')) {
235 dol_syslog(
'[MCP Server] Authentication KO: user '.$tmpuser->login.
' has no ai/assistant/use permission', LOG_NOTICE);
236 $this->httpcode = 403;
237 $this->error =
'The user owning this API key is not allowed to use the AI assistant';
241 $this->userid = $userid;
242 $this->
user = $tmpuser;
247 dol_syslog(
'[MCP Server] Unauthorized access attempt. IP='.(empty($_SERVER[
'REMOTE_ADDR']) ?
'unknown' : $_SERVER[
'REMOTE_ADDR']), LOG_WARNING);
250 $this->error =
'Unauthorized';
268 $challenge =
'Bearer realm="Dolibarr MCP"';
269 if ($resourcemetadataurl !==
'') {
270 $challenge .=
', resource_metadata="'.$resourcemetadataurl.
'"';
290 $sql =
"SELECT u.rowid, u.login, u.statut, oat.tokenstring as storedkey";
291 $sql .=
" FROM ".$this->db->prefix().
"oauth_token as oat";
292 $sql .=
" INNER JOIN ".$this->db->prefix().
"user as u ON u.rowid = oat.fk_user";
293 $sql .=
" WHERE (oat.tokenstring = '".$this->db->escape($credential).
"'";
294 $sql .=
" OR oat.tokenstring = '".$this->db->escape(
dolEncrypt($credential,
'',
'',
'dolibarr')).
"')";
295 $sql .=
" AND oat.service = 'dolibarr_rest_api'";
297 $sql =
"SELECT u.rowid, u.login, u.statut, u.api_key as storedkey";
298 $sql .=
" FROM ".$this->db->prefix().
"user as u";
299 $sql .=
" WHERE u.api_key = '".$this->db->escape($credential).
"'";
300 $sql .=
" OR u.api_key = '".$this->db->escape(
dolEncrypt($credential,
'',
'',
'dolibarr')).
"'";
303 $resql = $this->db->query($sql);
305 dol_syslog(
'[MCP Server] Authentication query failed: '.$this->db->lasterror(), LOG_ERR);
308 if ($this->db->num_rows($resql) != 1) {
314 $obj = $this->db->fetch_object($resql);
322 if (!hash_equals((
string)
dolDecrypt($obj->storedkey), $credential)) {
323 dol_syslog(
'[MCP Server] Authentication KO: key matched user '.$obj->login.
' but differs from the stored value', LOG_WARNING);
327 if (empty($obj->statut)) {
328 dol_syslog(
'[MCP Server] Authentication KO: user '.$obj->login.
' is disabled', LOG_NOTICE);
332 dol_syslog(
'[MCP Server] Request authenticated for user '.$obj->login, LOG_DEBUG);
334 return (
int) $obj->rowid;
authenticate($server=null, $get=null)
Authenticate the caller.
getCredential($server=null, $get=null)
Extract the credential presented by the caller.
const MODE_SHARED
Credential mode: the shared AI_MCP_API_KEY was presented.
__construct($db)
Constructor.
const MODE_USER
Credential mode: an individual user API key was presented.
getWwwAuthenticateHeader($resourcemetadataurl='')
Value of the WWW-Authenticate header to send with a 401.
fetchUserIdFromApiKey($credential)
Look up the active user owning this API key.
Class to manage Dolibarr users.
dol_string_nounprintableascii($str, $removetabcrlf=1)
Clean a string from all non printable ASCII chars (0x00-0x1F and 0x7F).
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.
$conf db user
Active Directory does not allow anonymous connections.
dolDecrypt($chain, $key='', $patterntotest='')
Decode a string with a symmetric encryption.
dolEncrypt($chain, $key='', $ciphering='', $forceseed='', $obfuscationmode='dolcrypt')
Encode a string with a symmetric encryption.