use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.
the class SamService method initializeWsmServiceAccount.
/**
* Register WSM's service account as a user in Sam if it isn't already. This should only need to
* register with Sam once per environment, so it is implemented lazily.
*/
private void initializeWsmServiceAccount() throws InterruptedException {
if (!wsmServiceAccountInitialized) {
String wsmAccessToken = null;
try {
wsmAccessToken = getWsmServiceAccountToken();
} catch (InternalServerErrorException e) {
// In cases where WSM is not running as a service account (e.g. unit tests), the above call
// will throw. This can be ignored now and later when the credentials are used again.
logger.warn("Failed to register WSM service account in Sam. This is expected for tests.", e);
return;
}
UsersApi usersApi = samUsersApi(wsmAccessToken);
// If registering the service account fails, all we can do is to keep trying.
if (!wsmServiceAccountRegistered(usersApi)) {
// retries internally
registerWsmServiceAccount(usersApi);
}
wsmServiceAccountInitialized = true;
}
}
use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.
the class SamService method getOrCreatePetSaCredentials.
/**
* Fetch credentials of a user's pet service account in a given project. This request to Sam will
* create the pet SA if it doesn't already exist.
*/
public AuthenticatedUserRequest getOrCreatePetSaCredentials(String projectId, AuthenticatedUserRequest userRequest) throws InterruptedException {
GoogleApi samGoogleApi = samGoogleApi(userRequest.getRequiredToken());
try {
String petEmail = getOrCreatePetSaEmail(projectId, userRequest.getRequiredToken());
String petToken = SamRetry.retry(() -> samGoogleApi.getPetServiceAccountToken(projectId, PET_SA_OAUTH_SCOPES));
// This should never happen, but it's more informative than an NPE from Optional.of
if (petToken == null) {
throw new InternalServerErrorException("Sam returned null pet service account token");
}
return new AuthenticatedUserRequest().email(petEmail).token(Optional.of(petToken));
} catch (ApiException apiException) {
throw SamExceptionFactory.create("Error getting pet service account token from Sam", apiException);
}
}
use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.
the class PetSaService method enablePetServiceAccountImpersonationWithEtag.
/**
* Grant a user's proxy group permission to impersonate their pet service account in a given
* workspace. Unlike other operations, this does not run as a flight because it only requires one
* write operation. This operation is idempotent.
*
* <p>The provided workspace must have a GCP context.
*
* <p>This method does not authenticate that the user should have access to impersonate their pet
* SA, callers should validate this first.
*
* <p>userToEnableEmail is separate from token because of RevokePetUsagePermissionStep.undoStep().
* If User A removes B from workspace, userToEnableEmail is B and token is from A's userRequest.
*
* @param workspaceId ID of the workspace to enable pet SA in
* @param userToEnableEmail The user whose proxy group will be granted permission.
* @param token Token for calling SAM.
* @param eTag GCP eTag which must match the pet SA's current policy. If null, this is ignored.
* @return The new IAM policy on the user's pet service account, or empty if the eTag value
* provided is non-null and does not match current IAM policy on the pet SA.
*/
public Optional<Policy> enablePetServiceAccountImpersonationWithEtag(UUID workspaceId, String userToEnableEmail, String token, @Nullable String eTag) {
String petSaEmail = SamRethrow.onInterrupted(() -> samService.getOrCreatePetSaEmail(gcpCloudContextService.getRequiredGcpProject(workspaceId), token), "enablePet");
String proxyGroupEmail = SamRethrow.onInterrupted(() -> samService.getProxyGroupEmail(userToEnableEmail, token), "enablePet");
String projectId = gcpCloudContextService.getRequiredGcpProject(workspaceId);
ServiceAccountName petSaName = ServiceAccountName.builder().email(petSaEmail).projectId(projectId).build();
try {
Policy saPolicy = crlService.getIamCow().projects().serviceAccounts().getIamPolicy(petSaName).execute();
// clobbering other changes.
if (eTag != null && !saPolicy.getEtag().equals(eTag)) {
logger.warn("GCP IAM policy eTag did not match expected value when granting pet SA access for user {} in workspace {}. This is normal for Step retries.", userToEnableEmail, workspaceId);
return Optional.empty();
}
Binding saUserBinding = new Binding().setRole(SERVICE_ACCOUNT_USER_ROLE).setMembers(ImmutableList.of("group:" + proxyGroupEmail));
// If no bindings exist, getBindings() returns null instead of an empty list.
List<Binding> bindingList = Optional.ofNullable(saPolicy.getBindings()).orElse(new ArrayList<>());
// GCP automatically de-duplicates bindings, so this will have no effect if the user already
// has permission to use their pet service account.
bindingList.add(saUserBinding);
saPolicy.setBindings(bindingList);
SetIamPolicyRequest request = new SetIamPolicyRequest().setPolicy(saPolicy);
return Optional.of(crlService.getIamCow().projects().serviceAccounts().setIamPolicy(petSaName, request).execute());
} catch (IOException e) {
throw new InternalServerErrorException("Error enabling user's proxy group to impersonate pet SA", e);
}
}
use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.
the class PetSaService method disablePetServiceAccountImpersonationWithEtag.
/**
* Revoke the permission to impersonate a pet service account granted by {@code
* enablePetServiceAccountImpersonation}. Unlike other operations, this does not run in a flight
* because it only requires one write operation. This operation is idempotent.
*
* <p>This method requires a user's pet service account email as input. As a transitive
* dependency, this also means the provided workspace must have a GCP context.
*
* <p>This method does not authenticate that the user should have access to impersonate their pet
* SA, callers should validate this first.
*
* @param workspaceId ID of the workspace to disable pet SA in
* @param userToDisableEmail The user losing access to pet SA
* @param userRequest This request's token will be used to authenticate SAM requests
* @param eTag GCP eTag which must match the pet SA's current policy. If null, this is ignored.
*/
public Optional<Policy> disablePetServiceAccountImpersonationWithEtag(UUID workspaceId, String userToDisableEmail, AuthenticatedUserRequest userRequest, @Nullable String eTag) {
String proxyGroupEmail = SamRethrow.onInterrupted(() -> samService.getProxyGroupEmail(userToDisableEmail, userRequest.getRequiredToken()), "disablePet");
String projectId = gcpCloudContextService.getRequiredGcpProject(workspaceId);
try {
Optional<ServiceAccountName> userToDisablePetSA = getUserPetSa(projectId, userToDisableEmail, userRequest);
if (userToDisablePetSA.isEmpty()) {
return Optional.empty();
}
Policy saPolicy = crlService.getIamCow().projects().serviceAccounts().getIamPolicy(userToDisablePetSA.get()).execute();
// clobbering other changes.
if (eTag != null && !saPolicy.getEtag().equals(eTag)) {
logger.warn("GCP IAM policy eTag did not match expected value when revoking pet SA access for user {} in workspace {}. This is normal for Step retries.", userToDisableEmail, workspaceId);
return Optional.empty();
}
Binding bindingToRemove = new Binding().setRole(SERVICE_ACCOUNT_USER_ROLE).setMembers(ImmutableList.of("group:" + proxyGroupEmail));
// If no bindings exist, getBindings() returns null instead of an empty list. If there are
// no policies, there is nothing to revoke, so this method is finished.
List<Binding> oldBindingList = saPolicy.getBindings();
if (oldBindingList == null) {
return Optional.empty();
}
List<Binding> newBindingsList = removeBinding(oldBindingList, bindingToRemove);
saPolicy.setBindings(newBindingsList);
SetIamPolicyRequest request = new SetIamPolicyRequest().setPolicy(saPolicy);
return Optional.of(crlService.getIamCow().projects().serviceAccounts().setIamPolicy(userToDisablePetSA.get(), request).execute());
} catch (IOException e) {
throw new InternalServerErrorException("Error disabling user's proxy group to impersonate pet SA", e);
}
}
use of bio.terra.common.exception.InternalServerErrorException in project terra-workspace-manager by DataBiosphere.
the class ControlledResourceSamPolicyBuilder method addWsmResourceOwnerPolicy.
/**
* Add WSM's service account as the owner of a controlled resource in Sam. Used for admin
* reassignment of resources. This assumes samService.initialize() has already been called, which
* should happen on start.
*/
private void addWsmResourceOwnerPolicy(CreateResourceRequestV2 request) {
try {
AccessPolicyMembershipV2 ownerPolicy = new AccessPolicyMembershipV2().addRolesItem(ControlledResourceIamRole.OWNER.toSamRole()).addMemberEmailsItem(GcpUtils.getWsmSaEmail());
request.putPoliciesItem(ControlledResourceIamRole.OWNER.toSamRole(), ownerPolicy);
} catch (InternalServerErrorException e) {
// In cases where WSM is not running as a service account (e.g. unit tests), the above call to
// get application default credentials will fail. This is fine, as those cases don't create
// real resources.
logger.warn("Failed to add WSM service account as resource owner Sam. This is expected for tests.", e);
}
}
Aggregations