Skip to content

Commit

Permalink
Fixed a problem updating the API host registry (#6995)
Browse files Browse the repository at this point in the history
* fix: a problem upgrading the API host registry data through /api/check-stored-api endpoint

The allow_run_as missing data in the API host registry could cause the
authentication used the internal user instead of the context of logger
user when run_as was enabled.

* chore(changelog): add entry

* fix: ensure the user authentication uses the related endpoint according to the configuration of run_as

- Ensure the user authentication uses the related endpoint according to the configuration of run_as
  Move the logic to decide the authentication (user or not run_as) to asCurrentUser.authenticate
- Fix when the `run_as: false` for a server API host, any login of an user caused the
  internal user token was replaced by the obtained for the logged user.

---------

Co-authored-by: Federico Rodriguez <federico.rodriguez@wazuh.com>
  • Loading branch information
Desvelao and asteriscos authored Sep 19, 2024
1 parent 2373b8c commit c3d75ea
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 147 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ All notable changes to the Wazuh app project will be documented in this file.

### Added

- Add feature to filter by field in the events table rows [#6977](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6991)
- Support for Wazuh 4.9.1
- Add feature to filter by field in the events table rows [#6977](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6991)

### Fixed

Expand All @@ -20,6 +20,7 @@ All notable changes to the Wazuh app project will be documented in this file.
- Fixed missing link to Vulnerabilities detection and Office 365 in the agent menu of `Endpoints Summary` [#6983](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6983)
- Fixed missing options depending on agent operating system in the agent configuration report [#6983](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6983)
- Fixed an style that affected the Discover plugin [#6989](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6989)
- Fixed a problem updating the API host registry in the GET /api/check-stored-api [#6995](https://github.com/wazuh/wazuh-dashboard-plugins/pull/6995)

### Changed

Expand Down
118 changes: 24 additions & 94 deletions plugins/main/server/controllers/wazuh-api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,9 @@ export class WazuhApiCtrl {
}
}
}
let token;
if (context.wazuh_core.manageHosts.isEnabledAuthWithRunAs(idHost)) {
token = await context.wazuh.api.client.asCurrentUser.authenticate(
idHost,
);
} else {
token = await context.wazuh.api.client.asInternalUser.authenticate(
idHost,
);
}
const token = await context.wazuh.api.client.asCurrentUser.authenticate(
idHost,
);

let textSecure = '';
if (context.wazuh.server.info.protocol === 'https') {
Expand Down Expand Up @@ -162,94 +155,31 @@ export class WazuhApiCtrl {
}

// If we have a valid response from the Wazuh API
if (
responseManagerInfo.status === HTTP_STATUS_CODES.OK &&
responseManagerInfo.data
) {
// Clear and update cluster information before being sent back to frontend
delete api.cluster_info;
const responseAgents =
await context.wazuh.api.client.asInternalUser.request(
'GET',
`/agents`,
{ params: { agents_list: '000' } },
{ apiHostID: id },
try {
const { status, manager, node, cluster } =
await context.wazuh_core.manageHosts.getRegistryDataByHost(
apiHostData,
{
throwError: true,
},
);

if (responseAgents.status === HTTP_STATUS_CODES.OK) {
const managerName =
responseAgents.data.data.affected_items[0].manager;
api.cluster_info = { status, manager, node, cluster };

const responseClusterStatus =
await context.wazuh.api.client.asInternalUser.request(
'GET',
`/cluster/status`,
{},
{ apiHostID: id },
);
if (responseClusterStatus.status === HTTP_STATUS_CODES.OK) {
if (responseClusterStatus.data.data.enabled === 'yes') {
const responseClusterLocalInfo =
await context.wazuh.api.client.asInternalUser.request(
'GET',
`/cluster/local/info`,
{},
{ apiHostID: id },
);
if (responseClusterLocalInfo.status === HTTP_STATUS_CODES.OK) {
const clusterEnabled =
responseClusterStatus.data.data.enabled === 'yes';
api.cluster_info = {
status: clusterEnabled ? 'enabled' : 'disabled',
manager: managerName,
node: responseClusterLocalInfo.data.data.affected_items[0]
.node,
cluster: clusterEnabled
? responseClusterLocalInfo.data.data.affected_items[0]
.cluster
: 'Disabled',
};
}
} else {
// Cluster mode is not active
api.cluster_info = {
status: 'disabled',
manager: managerName,
cluster: 'Disabled',
};
}
} else {
// Cluster mode is not active
api.cluster_info = {
status: 'disabled',
manager: managerName,
cluster: 'Disabled',
};
}

if (api.cluster_info) {
// Update cluster information in the wazuh-registry.json
await context.wazuh_core.manageHosts.updateRegistryByHost(
id,
api.cluster_info,
);

return response.ok({
body: {
statusCode: HTTP_STATUS_CODES.OK,
data: api,
idChanged: request.body.idChanged || null,
},
});
}
}
return response.ok({
body: {
statusCode: HTTP_STATUS_CODES.OK,
data: api,
idChanged: request.body.idChanged || null,
},
});
} catch (error) {
// If we have an invalid response from the Wazuh API
throw new Error(
responseManagerInfo.data.detail ||
`${api.url}:${api.port} is unreachable`,
);
}

// If we have an invalid response from the Wazuh API
throw new Error(
responseManagerInfo.data.detail ||
`${api.url}:${api.port} is unreachable`,
);
} catch (error) {
if (error.code === 'EPROTO') {
return response.ok({
Expand Down
1 change: 1 addition & 0 deletions plugins/main/server/routes/wazuh-api-http-status.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ const context = {
cacheAPIUserAllowRunAs: {
set: jest.fn(),
API_USER_STATUS_RUN_AS: {
UNABLE_TO_CHECK: -1,
ALL_DISABLED: 0,
USER_NOT_ALLOWED: 1,
HOST_DISABLED: 2,
Expand Down
21 changes: 3 additions & 18 deletions plugins/wazuh-core/common/api-user-status-run-as.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,8 @@
/**
* @example
* HOST = set in configuration
* USER = set in user interface
*
* ALL_DISABLED
* binary 00 = decimal 0 ---> USER 0 y HOST 0
*
* USER_NOT_ALLOWED
* binary 01 = decimal 1 ---> USER 0 y HOST 1
*
* HOST_DISABLED
* binary 10 = decimal 2 ---> USER 1 y HOST 0
*
* ENABLED
* binary 11 = decimal 3 ---> USER 1 y HOST 1
*/
export enum API_USER_STATUS_RUN_AS {
UNABLE_TO_CHECK = -1 /* Initial value or could not check the user can
use the run_as */,
ALL_DISABLED = 0, // Wazuh HOST and USER API user configured with run_as=false or undefined
USER_NOT_ALLOWED = 1, // Wazuh HOST API user configured with run_as=true in configuration but it has not run_as in Wazuh API
HOST_DISABLED = 2, // Wazuh HOST API user configured with run_as=false in configuration but it has not run_as in Wazuh API
HOST_DISABLED = 2, // Wazuh HOST API user configured with run_as=false in configuration but it has run_as in Wazuh API
ENABLED = 3, // Wazuh API user configured with run_as=true and allow run_as
}
73 changes: 57 additions & 16 deletions plugins/wazuh-core/server/services/manage-hosts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { HTTP_STATUS_CODES } from '../../common/constants';

interface IAPIHost {
id: string;
url: string;
username: string;
password: string;
port: number;
Expand All @@ -31,6 +32,13 @@ interface IAPIHostRegistry {
allow_run_as: API_USER_STATUS_RUN_AS;
}

interface GetRegistryDataByHostOptions {
/* this option lets to throw the error when trying to fetch the required data
of the API host that is used by the checkStoredAPI of /api/check-stored-api
endpoint */
throwError: boolean;
}

/**
* This service manages the API connections.
* Get API hosts configuration
Expand Down Expand Up @@ -141,6 +149,7 @@ export class ManageHosts {
*/
private async getRegistryDataByHost(
host: IAPIHost,
options: GetRegistryDataByHostOptions,
): Promise<IAPIHostRegistry> {
const apiHostID = host.id;
this.logger.debug(`Getting registry data from host [${apiHostID}]`);
Expand All @@ -150,7 +159,7 @@ export class ManageHosts {
node = null,
status = 'disabled',
cluster = 'Disabled',
allow_run_as = API_USER_STATUS_RUN_AS.ALL_DISABLED;
allow_run_as = API_USER_STATUS_RUN_AS.UNABLE_TO_CHECK;

try {
const responseAgents = await this.serverAPIClient.asInternalUser.request(
Expand All @@ -165,21 +174,24 @@ export class ManageHosts {
}

// Get allow_run_as
if (!host.run_as) {
allow_run_as = API_USER_STATUS_RUN_AS.HOST_DISABLED;
} else {
const responseAllowRunAs =
await this.serverAPIClient.asInternalUser.request(
'GET',
'/security/users/me',
{},
{ apiHostID },
);
if (this.isServerAPIClientResponseOk(responseAllowRunAs)) {
allow_run_as = responseAllowRunAs.data.data.affected_items[0]
.allow_run_as
const responseAllowRunAs =
await this.serverAPIClient.asInternalUser.request(
'GET',
'/security/users/me',
{},
{ apiHostID },
);
if (this.isServerAPIClientResponseOk(responseAllowRunAs)) {
const allow_run_as_response =
responseAllowRunAs.data.data.affected_items[0].allow_run_as;
if (host.run_as) {
allow_run_as = allow_run_as_response
? API_USER_STATUS_RUN_AS.ENABLED
: API_USER_STATUS_RUN_AS.USER_NOT_ALLOWED;
} else {
allow_run_as = allow_run_as_response
? API_USER_STATUS_RUN_AS.HOST_DISABLED
: API_USER_STATUS_RUN_AS.ALL_DISABLED;
}
}

Expand All @@ -191,7 +203,10 @@ export class ManageHosts {
{ apiHostID },
);

if (this.isServerAPIClientResponseOk(responseClusterStatus) && responseClusterStatus.data?.data?.enabled === 'yes') {
if (
this.isServerAPIClientResponseOk(responseClusterStatus) &&
responseClusterStatus.data?.data?.enabled === 'yes'
) {
status = 'enabled';

const responseClusterLocal =
Expand All @@ -207,7 +222,11 @@ export class ManageHosts {
cluster = responseClusterLocal.data.data.affected_items[0].cluster;
}
}
} catch (error) {}
} catch (error) {
if (options?.throwError) {
throw error;
}
}

const data = {
manager,
Expand Down Expand Up @@ -283,11 +302,33 @@ export class ManageHosts {
`API host with ID [${apiId}] was not found in the registry. This could be caused by a problem getting and storing the registry data or the API host was removed.`,
);
}
if (registryHost.allow_run_as === API_USER_STATUS_RUN_AS.UNABLE_TO_CHECK) {
throw new Error(
`API host with host ID [${apiId}] could not check the ability to use the run as. Ensure the API host is accesible and the internal user has the minimal permissions to check this capability.`,
);
}
if (registryHost.allow_run_as === API_USER_STATUS_RUN_AS.USER_NOT_ALLOWED) {
throw new Error(
`API host with host ID [${apiId}] misconfigured. The configurated API user is not allowed to use [run_as]. Allow it in the API user configuration or set [run_as] host setting with [false] value.`,
);
}

/* The allowed values to compare should be:
API_USER_STATUS_RUN_AS.ENABLED: use run_as
API_USER_STATUS_RUN_AS.HOST_DISABLED: not use run_as
API_USER_STATUS_RUN_AS.ALL_DISABLED: not use run_as
*/
if (
![
API_USER_STATUS_RUN_AS.ENABLED,
API_USER_STATUS_RUN_AS.HOST_DISABLED,
API_USER_STATUS_RUN_AS.ALL_DISABLED,
].includes(registryHost.allow_run_as)
) {
throw new Error(
`API host with host ID [${apiId}] has an unexpected value [${registryHost.allow_run_as}] stored in the registry. This could be caused by a problem getting and storing the registry data.`,
);
}
return registryHost.allow_run_as === API_USER_STATUS_RUN_AS.ENABLED;
}
}
Loading

0 comments on commit c3d75ea

Please sign in to comment.