-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PLAT-14225] Implement v2 Group Mapping APIs
Summary: Add the following v2 Group Mapping CRUD APIs : ``` GET /customers/:cUUID/auth/group_mappings Response body: [ { "group_identifier": "test-group1", "uuid": "b0968020-5626-4ae5-b516-d4d77e5302c8", "type": "OIDC", "role_resource_definitions": [ { "role_uuid": "f3671ea7-6579-4fc0-ba33-f8da45ff19da" }, { "role_uuid": "9ce94a1f-3ed7-4a2f-8a6a-bda354d2dd1b", "resource_group": { "resource_definition_set": [ { "resource_type": "UNIVERSE", "allow_all": true, "resource_uuid_set": [] }, { "resource_type": "OTHER", "allow_all": false, "resource_uuid_set": [ "f33e3c9b-75ab-4c30-80ad-cba85646ea39" ] } ] } } ] } ] PUT v2/customers/:cUUID/auth/group_mappings Request body same as above. DELETE /customers/:custUUID/auth/group_mappings/:groupUUID ``` The diff also has migrations and other rbac changes required to add role bindings for Groups. Please refer to the design doc for complete context - https://docs.google.com/document/d/1qGYu6swY8xWFzqhNWZ6uKHHtKSO9847lm2I0sDB5okU Test Plan: Manually tested all changes. UTs pending. Reviewers: #yba-api-review, sneelakantan, svarshney, skurapati Reviewed By: #yba-api-review, sneelakantan Subscribers: sneelakantan, sanketh, yugaware Differential Revision: https://phorge.dev.yugabyte.com/D36269
- Loading branch information
1 parent
7786cf7
commit 95fb188
Showing
31 changed files
with
1,411 additions
and
16 deletions.
There are no files selected for viewing
31 changes: 31 additions & 0 deletions
31
managed/src/main/java/api/v2/controllers/AuthenticationApiControllerImp.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
// Copyright (c) Yugabyte, Inc. | ||
|
||
package api.v2.controllers; | ||
|
||
import api.v2.handlers.AuthenticationHandler; | ||
import api.v2.models.GroupMappingSpec; | ||
import com.google.inject.Inject; | ||
import java.util.List; | ||
import java.util.UUID; | ||
import play.mvc.Http; | ||
|
||
public class AuthenticationApiControllerImp extends AuthenticationApiControllerImpInterface { | ||
|
||
@Inject AuthenticationHandler authHandler; | ||
|
||
@Override | ||
public List<GroupMappingSpec> listMappings(Http.Request request, UUID cUUID) throws Exception { | ||
return authHandler.listMappings(cUUID); | ||
} | ||
|
||
@Override | ||
public void updateGroupMappings( | ||
Http.Request request, UUID cUUID, List<GroupMappingSpec> groupMappingSpec) throws Exception { | ||
authHandler.updateGroupMappings(request, cUUID, groupMappingSpec); | ||
} | ||
|
||
@Override | ||
public void deleteGroupMappings(Http.Request request, UUID cUUID, UUID gUUID) throws Exception { | ||
authHandler.deleteGroupMappings(request, cUUID, gUUID); | ||
} | ||
} |
181 changes: 181 additions & 0 deletions
181
managed/src/main/java/api/v2/handlers/AuthenticationHandler.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,181 @@ | ||
// Copyright (c) Yugabyte, Inc. | ||
|
||
package api.v2.handlers; | ||
|
||
import static play.mvc.Http.Status.BAD_REQUEST; | ||
import static play.mvc.Http.Status.NOT_FOUND; | ||
|
||
import api.v2.mappers.RoleResourceDefinitionMapper; | ||
import api.v2.models.GroupMappingSpec; | ||
import api.v2.models.GroupMappingSpec.TypeEnum; | ||
import com.google.inject.Inject; | ||
import com.google.inject.Singleton; | ||
import com.yugabyte.yw.common.PlatformServiceException; | ||
import com.yugabyte.yw.common.config.GlobalConfKeys; | ||
import com.yugabyte.yw.common.config.RuntimeConfGetter; | ||
import com.yugabyte.yw.common.rbac.RoleBindingUtil; | ||
import com.yugabyte.yw.common.rbac.RoleResourceDefinition; | ||
import com.yugabyte.yw.controllers.TokenAuthenticator; | ||
import com.yugabyte.yw.models.GroupMappingInfo; | ||
import com.yugabyte.yw.models.GroupMappingInfo.GroupType; | ||
import com.yugabyte.yw.models.rbac.Role; | ||
import com.yugabyte.yw.models.rbac.RoleBinding; | ||
import com.yugabyte.yw.models.rbac.RoleBinding.RoleBindingType; | ||
import io.ebean.annotation.Transactional; | ||
import java.util.ArrayList; | ||
import java.util.List; | ||
import java.util.UUID; | ||
import lombok.extern.slf4j.Slf4j; | ||
import play.mvc.Http; | ||
|
||
@Slf4j | ||
@Singleton | ||
public class AuthenticationHandler { | ||
|
||
@Inject RuntimeConfGetter confGetter; | ||
@Inject TokenAuthenticator tokenAuthenticator; | ||
@Inject RoleBindingUtil roleBindingUtil; | ||
|
||
public List<GroupMappingSpec> listMappings(UUID cUUID) throws Exception { | ||
|
||
checkRuntimeConfig(); | ||
|
||
List<GroupMappingInfo> groupInfoList = | ||
GroupMappingInfo.find.query().where().eq("customer_uuid", cUUID).findList(); | ||
List<GroupMappingSpec> specList = new ArrayList<GroupMappingSpec>(); | ||
for (GroupMappingInfo info : groupInfoList) { | ||
GroupMappingSpec spec = | ||
new GroupMappingSpec() | ||
.groupIdentifier(info.getIdentifier()) | ||
.type(TypeEnum.valueOf(info.getType().toString())) | ||
.uuid(info.getGroupUUID()); | ||
|
||
List<RoleResourceDefinition> roleResourceDefinitions = new ArrayList<>(); | ||
if (confGetter.getGlobalConf(GlobalConfKeys.useNewRbacAuthz)) { | ||
// fetch all role rolebindings for the current group | ||
List<RoleBinding> roleBindingList = RoleBinding.getAll(info.getGroupUUID()); | ||
for (RoleBinding rb : roleBindingList) { | ||
RoleResourceDefinition roleResourceDefinition = | ||
new RoleResourceDefinition(rb.getRole().getRoleUUID(), rb.getResourceGroup()); | ||
roleResourceDefinitions.add(roleResourceDefinition); | ||
} | ||
} else { | ||
// No role bindings present if RBAC is off. | ||
RoleResourceDefinition rrd = new RoleResourceDefinition(); | ||
rrd.setRoleUUID(info.getRoleUUID()); | ||
roleResourceDefinitions.add(rrd); | ||
} | ||
spec.setRoleResourceDefinitions( | ||
RoleResourceDefinitionMapper.INSTANCE.toV2RoleResourceDefinitionList( | ||
roleResourceDefinitions)); | ||
specList.add(spec); | ||
} | ||
return specList; | ||
} | ||
|
||
@Transactional | ||
public void updateGroupMappings( | ||
Http.Request request, UUID cUUID, List<GroupMappingSpec> groupMappingSpec) { | ||
boolean isSuperAdmin = tokenAuthenticator.superAdminAuthentication(request); | ||
if (!isSuperAdmin) { | ||
throw new PlatformServiceException(BAD_REQUEST, "Only SuperAdmin can create group mappings!"); | ||
} | ||
|
||
checkRuntimeConfig(); | ||
|
||
for (GroupMappingSpec mapping : groupMappingSpec) { | ||
GroupMappingInfo mappingInfo = | ||
GroupMappingInfo.find | ||
.query() | ||
.where() | ||
.eq("customer_uuid", cUUID) | ||
.ieq("identifier", mapping.getGroupIdentifier()) | ||
.findOne(); | ||
|
||
if (mappingInfo == null) { | ||
// new entry for new group | ||
log.info("Adding new group mapping entry for group: " + mapping.getGroupIdentifier()); | ||
mappingInfo = | ||
GroupMappingInfo.create( | ||
cUUID, | ||
mapping.getGroupIdentifier(), | ||
GroupType.valueOf(mapping.getType().toString())); | ||
} else { | ||
// clear role bindings for existing group | ||
clearRoleBindings(mappingInfo); | ||
} | ||
|
||
List<RoleResourceDefinition> roleResourceDefinitions = | ||
RoleResourceDefinitionMapper.INSTANCE.toV1RoleResourceDefinitionList( | ||
mapping.getRoleResourceDefinitions()); | ||
|
||
roleBindingUtil.validateRoles(cUUID, roleResourceDefinitions); | ||
roleBindingUtil.validateResourceGroups(cUUID, roleResourceDefinitions); | ||
|
||
if (confGetter.getGlobalConf(GlobalConfKeys.useNewRbacAuthz)) { | ||
// Add role bindings if rbac is on. | ||
for (RoleResourceDefinition rrd : roleResourceDefinitions) { | ||
Role rbacRole = Role.getOrBadRequest(cUUID, rrd.getRoleUUID()); | ||
RoleBinding.create(mappingInfo, RoleBindingType.Custom, rbacRole, rrd.getResourceGroup()); | ||
} | ||
// This role will be ignored when rbac is on. | ||
mappingInfo.setRoleUUID(Role.get(cUUID, "ConnectOnly").getRoleUUID()); | ||
} else { | ||
validate(roleResourceDefinitions); | ||
mappingInfo.setRoleUUID(roleResourceDefinitions.get(0).getRoleUUID()); | ||
} | ||
mappingInfo.save(); | ||
} | ||
} | ||
|
||
@Transactional | ||
public void deleteGroupMappings(Http.Request request, UUID cUUID, UUID gUUID) { | ||
boolean isSuperAdmin = tokenAuthenticator.superAdminAuthentication(request); | ||
if (!isSuperAdmin) { | ||
throw new PlatformServiceException(BAD_REQUEST, "Only SuperAdmin can delete group mappings!"); | ||
} | ||
|
||
checkRuntimeConfig(); | ||
|
||
GroupMappingInfo entity = | ||
GroupMappingInfo.find | ||
.query() | ||
.where() | ||
.eq("customer_uuid", cUUID) | ||
.eq("uuid", gUUID) | ||
.findOne(); | ||
if (entity == null) { | ||
throw new PlatformServiceException(NOT_FOUND, "No group mapping found with uuid: " + gUUID); | ||
} | ||
|
||
// Delete all role bindings | ||
clearRoleBindings(entity); | ||
log.info("Deleting Group Mapping with name: " + entity.getIdentifier()); | ||
entity.delete(); | ||
} | ||
|
||
private void clearRoleBindings(GroupMappingInfo mappingInfo) { | ||
log.info("Clearing role bindings for group: " + mappingInfo.getIdentifier()); | ||
List<RoleBinding> list = RoleBinding.getAll(mappingInfo.getGroupUUID()); | ||
list.forEach(rb -> rb.delete()); | ||
} | ||
|
||
private void checkRuntimeConfig() { | ||
if (!confGetter.getGlobalConf(GlobalConfKeys.groupMappingRbac)) { | ||
throw new PlatformServiceException( | ||
BAD_REQUEST, "yb.security.group_mapping_rbac_support runtime config is disabled!"); | ||
} | ||
} | ||
|
||
/** | ||
* Validation to make sure only a single system role is present when RBAC is off. | ||
* | ||
* @param cUUID | ||
* @param rrdList | ||
*/ | ||
private void validate(List<RoleResourceDefinition> rrdList) { | ||
if (rrdList.size() != 1) { | ||
throw new PlatformServiceException(BAD_REQUEST, "Need to specify a single system role!"); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
managed/src/main/java/api/v2/mappers/ResourceGroupMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
// Copyright (c) Yugabyte, Inc. | ||
|
||
package api.v2.mappers; | ||
|
||
import api.v2.models.ResourceDefinitionSpec; | ||
import api.v2.models.ResourceGroupSpec; | ||
import com.yugabyte.yw.models.rbac.ResourceGroup; | ||
import com.yugabyte.yw.models.rbac.ResourceGroup.ResourceDefinition; | ||
import org.mapstruct.InheritInverseConfiguration; | ||
import org.mapstruct.Mapper; | ||
import org.mapstruct.Mapping; | ||
import org.mapstruct.factory.Mappers; | ||
|
||
@Mapper(config = CentralConfig.class) | ||
public interface ResourceGroupMapper { | ||
ResourceGroupMapper INSTANCE = Mappers.getMapper(ResourceGroupMapper.class); | ||
|
||
ResourceGroupSpec toV2ResourceGroup(ResourceGroup v1ResourceGroup); | ||
|
||
ResourceGroup toV1ResourceGroup(ResourceGroupSpec v2ResourceGroup); | ||
|
||
@Mapping(target = "resourceUuidSet", source = "resourceUUIDSet") | ||
ResourceDefinitionSpec toV2ResourceDefinitionSpec(ResourceDefinition v1ResourceDefinition); | ||
|
||
@InheritInverseConfiguration | ||
ResourceDefinition toV1ResourceDefinitionSpec(ResourceDefinitionSpec v2ResourceDefinition); | ||
} |
32 changes: 32 additions & 0 deletions
32
managed/src/main/java/api/v2/mappers/RoleResourceDefinitionMapper.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
// Copyright (c) Yugabyte, Inc. | ||
|
||
package api.v2.mappers; | ||
|
||
import api.v2.models.RoleResourceDefinitionSpec; | ||
import com.yugabyte.yw.common.rbac.RoleResourceDefinition; | ||
import java.util.List; | ||
import org.mapstruct.InheritInverseConfiguration; | ||
import org.mapstruct.Mapper; | ||
import org.mapstruct.Mapping; | ||
import org.mapstruct.factory.Mappers; | ||
|
||
@Mapper( | ||
config = CentralConfig.class, | ||
uses = {ResourceGroupMapper.class}) | ||
public interface RoleResourceDefinitionMapper { | ||
RoleResourceDefinitionMapper INSTANCE = Mappers.getMapper(RoleResourceDefinitionMapper.class); | ||
|
||
@Mapping(target = "roleUuid", source = "roleUUID") | ||
RoleResourceDefinitionSpec toV2RoleResourceDefinition( | ||
RoleResourceDefinition v1RoleResourceDefinition); | ||
|
||
List<RoleResourceDefinitionSpec> toV2RoleResourceDefinitionList( | ||
List<RoleResourceDefinition> v1RoleResourceDefinition); | ||
|
||
@InheritInverseConfiguration | ||
RoleResourceDefinition toV1RoleResourceDefinition( | ||
RoleResourceDefinitionSpec v2RoleResourceDefinitionSpec); | ||
|
||
List<RoleResourceDefinition> toV1RoleResourceDefinitionList( | ||
List<RoleResourceDefinitionSpec> v2RoleResourceDefinition); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.