Skip to content

Commit

Permalink
feat: implement deletePrincipal and lookupPrincipal (#1970)
Browse files Browse the repository at this point in the history
  • Loading branch information
roaminggypsy authored Dec 18, 2024
1 parent f0a2c0d commit d2c9459
Show file tree
Hide file tree
Showing 5 changed files with 497 additions and 0 deletions.
34 changes: 34 additions & 0 deletions src/main/kotlin/org/wfanet/measurement/access/service/Errors.kt
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,40 @@ class PrincipalTypeNotSupportedException(
cause,
)

class PrincipalNotFoundForUserException(issuer: String, subject: String, cause: Throwable? = null) :
ServiceException(
Errors.Reason.PRINCIPAL_NOT_FOUND_FOR_USER,
"Principal not found for user with issuer $issuer and subject $subject",
mapOf(Errors.Metadata.ISSUER to issuer, Errors.Metadata.SUBJECT to subject),
cause,
)

class PrincipalNotFoundForTlsClientException(
authorityKeyIdentifier: String,
cause: Throwable? = null,
) :
ServiceException(
reason,
"Principal not found for tls client with authority key identifier $authorityKeyIdentifier",
mapOf(Errors.Metadata.AUTHORITY_KEY_IDENTIFIER to authorityKeyIdentifier),
cause,
) {
companion object : Factory<PrincipalNotFoundForTlsClientException>() {
override val reason: Errors.Reason
get() = Errors.Reason.PRINCIPAL_NOT_FOUND_FOR_TLS_CLIENT

override fun fromInternal(
internalMetadata: Map<InternalErrors.Metadata, String>,
cause: Throwable,
): PrincipalNotFoundForTlsClientException {
return PrincipalNotFoundForTlsClientException(
internalMetadata.getValue(InternalErrors.Metadata.AUTHORITY_KEY_IDENTIFIER),
cause,
)
}
}
}

class PermissionNotFoundException(name: String, cause: Throwable? = null) :
ServiceException(
reason,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,24 +16,31 @@

package org.wfanet.measurement.access.service.v1alpha

import com.google.protobuf.Empty
import io.grpc.Status
import io.grpc.StatusException
import org.wfanet.measurement.access.service.InvalidFieldValueException
import org.wfanet.measurement.access.service.PrincipalAlreadyExistsException
import org.wfanet.measurement.access.service.PrincipalKey
import org.wfanet.measurement.access.service.PrincipalNotFoundException
import org.wfanet.measurement.access.service.PrincipalNotFoundForTlsClientException
import org.wfanet.measurement.access.service.PrincipalNotFoundForUserException
import org.wfanet.measurement.access.service.PrincipalTypeNotSupportedException
import org.wfanet.measurement.access.service.RequiredFieldNotSetException
import org.wfanet.measurement.access.service.internal.Errors as InternalErrors
import org.wfanet.measurement.access.v1alpha.CreatePrincipalRequest
import org.wfanet.measurement.access.v1alpha.DeletePrincipalRequest
import org.wfanet.measurement.access.v1alpha.GetPrincipalRequest
import org.wfanet.measurement.access.v1alpha.LookupPrincipalRequest
import org.wfanet.measurement.access.v1alpha.Principal
import org.wfanet.measurement.access.v1alpha.PrincipalsGrpcKt
import org.wfanet.measurement.common.api.ResourceIds
import org.wfanet.measurement.internal.access.Principal as InternalPrincipal
import org.wfanet.measurement.internal.access.PrincipalsGrpcKt.PrincipalsCoroutineStub as InternalPrincipalsCoroutineStub
import org.wfanet.measurement.internal.access.createUserPrincipalRequest as internalCreateUserPrincipalRequest
import org.wfanet.measurement.internal.access.deletePrincipalRequest as internalDeletePrincipalRequest
import org.wfanet.measurement.internal.access.getPrincipalRequest as internalGetPrincipalRequest
import org.wfanet.measurement.internal.access.lookupPrincipalRequest as internalLookupPrincipalRequest

class PrincipalsService(private val internalPrincipalsStub: InternalPrincipalsCoroutineStub) :
PrincipalsGrpcKt.PrincipalsCoroutineImplBase() {
Expand Down Expand Up @@ -147,4 +154,115 @@ class PrincipalsService(private val internalPrincipalsStub: InternalPrincipalsCo

return internalResponse.toPrincipal()
}

override suspend fun deletePrincipal(request: DeletePrincipalRequest): Empty {
if (request.name.isEmpty()) {
throw RequiredFieldNotSetException("name")
.asStatusRuntimeException(Status.Code.INVALID_ARGUMENT)
}
val principalKey =
PrincipalKey.fromName(request.name)
?: throw InvalidFieldValueException("name")
.asStatusRuntimeException(Status.Code.INVALID_ARGUMENT)

try {
internalPrincipalsStub.deletePrincipal(
internalDeletePrincipalRequest { principalResourceId = principalKey.principalId }
)
} catch (e: StatusException) {
throw when (InternalErrors.getReason(e)) {
InternalErrors.Reason.PRINCIPAL_NOT_FOUND ->
PrincipalNotFoundException(request.name, e)
.asStatusRuntimeException(Status.Code.NOT_FOUND)
InternalErrors.Reason.PRINCIPAL_TYPE_NOT_SUPPORTED ->
PrincipalTypeNotSupportedException(Principal.IdentityCase.TLS_CLIENT, e)
.asStatusRuntimeException(Status.Code.FAILED_PRECONDITION)
InternalErrors.Reason.PRINCIPAL_ALREADY_EXISTS,
InternalErrors.Reason.PRINCIPAL_NOT_FOUND_FOR_USER,
InternalErrors.Reason.PRINCIPAL_NOT_FOUND_FOR_TLS_CLIENT,
InternalErrors.Reason.PERMISSION_NOT_FOUND,
InternalErrors.Reason.PERMISSION_NOT_FOUND_FOR_ROLE,
InternalErrors.Reason.ROLE_NOT_FOUND,
InternalErrors.Reason.ROLE_ALREADY_EXISTS,
InternalErrors.Reason.POLICY_NOT_FOUND,
InternalErrors.Reason.POLICY_NOT_FOUND_FOR_PROTECTED_RESOURCE,
InternalErrors.Reason.POLICY_ALREADY_EXISTS,
InternalErrors.Reason.POLICY_BINDING_MEMBERSHIP_ALREADY_EXISTS,
InternalErrors.Reason.POLICY_BINDING_MEMBERSHIP_NOT_FOUND,
InternalErrors.Reason.RESOURCE_TYPE_NOT_FOUND_IN_PERMISSION,
InternalErrors.Reason.REQUIRED_FIELD_NOT_SET,
InternalErrors.Reason.INVALID_FIELD_VALUE,
InternalErrors.Reason.ETAG_MISMATCH,
null -> Status.INTERNAL.withCause(e).asRuntimeException()
}
}

return Empty.getDefaultInstance()
}

override suspend fun lookupPrincipal(request: LookupPrincipalRequest): Principal {
when (request.lookupKeyCase) {
LookupPrincipalRequest.LookupKeyCase.USER -> {
if (request.user.issuer.isEmpty()) {
throw RequiredFieldNotSetException("user.issuer")
.asStatusRuntimeException(Status.Code.INVALID_ARGUMENT)
}

if (request.user.subject.isEmpty()) {
throw RequiredFieldNotSetException("user.subject")
.asStatusRuntimeException(Status.Code.INVALID_ARGUMENT)
}
}
LookupPrincipalRequest.LookupKeyCase.TLS_CLIENT -> {
if (request.tlsClient.authorityKeyIdentifier.isEmpty) {
throw RequiredFieldNotSetException("tlsclient.authoritykeyidentifier")
.asStatusRuntimeException(Status.Code.INVALID_ARGUMENT)
}
}
else ->
throw RequiredFieldNotSetException("lookup_key")
.asStatusRuntimeException(Status.Code.INVALID_ARGUMENT)
}

val internalResponse: InternalPrincipal =
try {
internalPrincipalsStub.lookupPrincipal(
internalLookupPrincipalRequest {
if (request.lookupKeyCase == LookupPrincipalRequest.LookupKeyCase.USER) {
user = request.user.toInternal()
} else {
tlsClient = request.tlsClient.toInternal()
}
}
)
} catch (e: StatusException) {
throw when (InternalErrors.getReason(e)) {
InternalErrors.Reason.PRINCIPAL_NOT_FOUND_FOR_USER ->
PrincipalNotFoundForUserException(request.user.issuer, request.user.subject, e)
.asStatusRuntimeException(Status.Code.NOT_FOUND)
InternalErrors.Reason.PRINCIPAL_NOT_FOUND_FOR_TLS_CLIENT ->
PrincipalNotFoundForTlsClientException.fromInternal(e)
.asStatusRuntimeException(e.status.code)
InternalErrors.Reason.PRINCIPAL_ALREADY_EXISTS,
InternalErrors.Reason.PRINCIPAL_NOT_FOUND,
InternalErrors.Reason.PRINCIPAL_TYPE_NOT_SUPPORTED,
InternalErrors.Reason.PERMISSION_NOT_FOUND,
InternalErrors.Reason.PERMISSION_NOT_FOUND_FOR_ROLE,
InternalErrors.Reason.ROLE_NOT_FOUND,
InternalErrors.Reason.ROLE_ALREADY_EXISTS,
InternalErrors.Reason.POLICY_NOT_FOUND,
InternalErrors.Reason.POLICY_NOT_FOUND_FOR_PROTECTED_RESOURCE,
InternalErrors.Reason.POLICY_ALREADY_EXISTS,
InternalErrors.Reason.POLICY_BINDING_MEMBERSHIP_ALREADY_EXISTS,
InternalErrors.Reason.POLICY_BINDING_MEMBERSHIP_NOT_FOUND,
InternalErrors.Reason.RESOURCE_TYPE_NOT_FOUND_IN_PERMISSION,
InternalErrors.Reason.REQUIRED_FIELD_NOT_SET,
InternalErrors.Reason.INVALID_FIELD_VALUE,
InternalErrors.Reason.ETAG_MISMATCH,
null -> Status.INTERNAL.withCause(e).asRuntimeException()
}
}

return internalResponse.toPrincipal()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import org.wfanet.measurement.access.v1alpha.principal
import org.wfanet.measurement.access.v1alpha.role
import org.wfanet.measurement.internal.access.Principal as InternalPrincipal
import org.wfanet.measurement.internal.access.PrincipalKt.oAuthUser as internalOAuthUser
import org.wfanet.measurement.internal.access.PrincipalKt.tlsClient as internalTlsClient
import org.wfanet.measurement.internal.access.Role as InternalRole

fun InternalPrincipal.toPrincipal(): Principal {
Expand Down Expand Up @@ -72,3 +73,8 @@ fun Principal.OAuthUser.toInternal(): InternalPrincipal.OAuthUser {
subject = source.subject
}
}

fun Principal.TlsClient.toInternal(): InternalPrincipal.TlsClient {
val source = this
return internalTlsClient { authorityKeyIdentifier = source.authorityKeyIdentifier }
}
Original file line number Diff line number Diff line change
Expand Up @@ -47,11 +47,19 @@ service Principals {
// Deletes a `Principal`.
//
// This will also remove the `Principal` from all `Policy` bindings.
//
// Error reasons:
// * `PRINCIPAL_NOT_FOUND`
// * `PRINCIPAL_TYPE_NOT_SUPPORTED`
rpc DeletePrincipal(DeletePrincipalRequest) returns (google.protobuf.Empty) {
option (google.api.method_signature) = "name";
}

// Looks up a `Principal` by lookup key.
//
// Error reasons:
// * `PRINCIPAL_NOT_FOUND_FOR_USER`
// * `PRINCIPAL_NOT_FOUND_FOR_TLS_CLIENT`
rpc LookupPrincipal(LookupPrincipalRequest) returns (Principal);
}

Expand Down
Loading

0 comments on commit d2c9459

Please sign in to comment.