* ValidateAndGrantInheritedRoles validates all parent roles and grants them. * Enforces that readWriteAnyDatabase and clusterAdmin must be specified together. */
| 1714 | * Enforces that readWriteAnyDatabase and clusterAdmin must be specified together. |
| 1715 | */ |
| 1716 | static void |
| 1717 | ValidateAndGrantInheritedRoles(const CreateRoleSpec *createRoleSpec) |
| 1718 | { |
| 1719 | HASH_SEQ_STATUS status; |
| 1720 | char *entry; |
| 1721 | bool hasReadWrite = false; |
| 1722 | bool hasClusterAdmin = false; |
| 1723 | |
| 1724 | hash_seq_init(&status, createRoleSpec->parentRoles); |
| 1725 | while ((entry = hash_seq_search(&status)) != NULL) |
| 1726 | { |
| 1727 | const char *roleName = entry; |
| 1728 | |
| 1729 | if (strcmp(roleName, "readWriteAnyDatabase") == 0) |
| 1730 | { |
| 1731 | hasReadWrite = true; |
| 1732 | } |
| 1733 | else if (strcmp(roleName, "clusterAdmin") == 0) |
| 1734 | { |
| 1735 | hasClusterAdmin = true; |
| 1736 | } |
| 1737 | } |
| 1738 | |
| 1739 | if (hasReadWrite != hasClusterAdmin) |
| 1740 | { |
| 1741 | ereport(ERROR, (errcode(ERRCODE_DOCUMENTDB_BADVALUE), |
| 1742 | errmsg( |
| 1743 | "Roles specified are invalid. 'readWriteAnyDatabase' and 'clusterAdmin' must be specified together."), |
| 1744 | errdetail_log( |
| 1745 | "Roles specified are invalid. 'readWriteAnyDatabase' and 'clusterAdmin' must be specified together."))); |
| 1746 | } |
| 1747 | |
| 1748 | /* |
| 1749 | * If both readWriteAnyDatabase and clusterAdmin are specified, grant |
| 1750 | * ApiAdminRoleV2 once (which provides both capabilities). |
| 1751 | */ |
| 1752 | bool grantedApiAdminRole = false; |
| 1753 | if (hasReadWrite && hasClusterAdmin) |
| 1754 | { |
| 1755 | grantedApiAdminRole = true; |
| 1756 | GrantRoleInheritance(ApiAdminRoleV2, createRoleSpec->roleName); |
| 1757 | } |
| 1758 | |
| 1759 | hash_seq_init(&status, createRoleSpec->parentRoles); |
| 1760 | while ((entry = hash_seq_search(&status)) != NULL) |
| 1761 | { |
| 1762 | const char *nativeRoleName = entry; |
| 1763 | const char *internalRoleName = GetInternalRoleName(nativeRoleName); |
| 1764 | |
| 1765 | /* |
| 1766 | * Skip readWriteAnyDatabase and clusterAdmin if we already granted |
| 1767 | * ApiAdminRoleV2, which provides both capabilities. |
| 1768 | */ |
| 1769 | if (grantedApiAdminRole && |
| 1770 | (strcmp(internalRoleName, ApiReadWriteRole) == 0 || |
| 1771 | strcmp(internalRoleName, ApiClusterAdminRole) == 0)) |
| 1772 | { |
| 1773 | continue; |
no test coverage detected