You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
boundary/internal/daemon/controller/handlers/list_token.go

187 lines
6.2 KiB

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package handlers
import (
"context"
"github.com/hashicorp/boundary/internal/errors"
pbs "github.com/hashicorp/boundary/internal/gen/controller/api/services"
"github.com/hashicorp/boundary/internal/listtoken"
"github.com/hashicorp/boundary/internal/types/resource"
"github.com/mr-tron/base58"
"google.golang.org/grpc/codes"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/types/known/timestamppb"
)
// ParseListToken parses a list token from the input, returning
// an error if the parsing fails.
func ParseListToken(
ctx context.Context,
token string,
expectedResourceType resource.Type,
expectedGrantsHash []byte,
) (*listtoken.Token, error) {
const op = "handlers.ParseListToken"
marshaled, err := base58.Decode(token)
if err != nil {
return nil, errors.Wrap(ctx, err, op)
}
var tok pbs.ListToken
if err := proto.Unmarshal(marshaled, &tok); err != nil {
return nil, errors.Wrap(ctx, err, op)
}
var listToken *listtoken.Token
switch st := tok.Token.(type) {
case *pbs.ListToken_PaginationToken:
listToken, err = listtoken.NewPagination(
ctx,
tok.CreateTime.AsTime(),
ListTokenResourceToResource(tok.ResourceType),
tok.GrantsHash,
st.PaginationToken.LastItemId,
st.PaginationToken.LastItemCreateTime.AsTime(),
)
if err != nil {
return nil, err
}
case *pbs.ListToken_StartRefreshToken:
listToken, err = listtoken.NewStartRefresh(
ctx,
tok.CreateTime.AsTime(),
ListTokenResourceToResource(tok.ResourceType),
tok.GrantsHash,
st.StartRefreshToken.PreviousDeletedIdsTime.AsTime(),
st.StartRefreshToken.PreviousPhaseUpperBound.AsTime(),
)
if err != nil {
return nil, err
}
case *pbs.ListToken_RefreshToken:
listToken, err = listtoken.NewRefresh(
ctx,
tok.CreateTime.AsTime(),
ListTokenResourceToResource(tok.ResourceType),
tok.GrantsHash,
st.RefreshToken.PreviousDeletedIdsTime.AsTime(),
st.RefreshToken.PhaseUpperBound.AsTime(),
st.RefreshToken.PhaseLowerBound.AsTime(),
st.RefreshToken.LastItemId,
st.RefreshToken.LastItemUpdateTime.AsTime(),
)
if err != nil {
return nil, err
}
default:
return nil, ApiErrorWithCodeAndMessage(codes.InvalidArgument, "unexpected list token subtype: %T", st)
}
if err := listToken.Validate(ctx, expectedResourceType, expectedGrantsHash); err != nil {
return nil, err
}
return listToken, nil
}
// MarshalListToken assembles and marshals a list token to its string representation.
func MarshalListToken(ctx context.Context, token *listtoken.Token, resourceType pbs.ResourceType) (string, error) {
const op = "handlers.MarshalListToken"
switch {
case token == nil:
return "", errors.New(ctx, errors.InvalidParameter, op, "token is required")
case resourceType == pbs.ResourceType_RESOURCE_TYPE_UNSPECIFIED:
return "", errors.New(ctx, errors.InvalidParameter, op, "missing resource type")
case token.ResourceType != ListTokenResourceToResource(resourceType):
return "", errors.New(ctx, errors.Internal, op, "list token resource type does not match expected resource type")
}
lt := &pbs.ListToken{
CreateTime: timestamppb.New(token.CreateTime),
ResourceType: resourceType,
GrantsHash: token.GrantsHash,
}
switch st := token.Subtype.(type) {
case *listtoken.PaginationToken:
lt.Token = &pbs.ListToken_PaginationToken{
PaginationToken: &pbs.PaginationToken{
LastItemId: st.LastItemId,
LastItemCreateTime: timestamppb.New(st.LastItemCreateTime),
},
}
case *listtoken.StartRefreshToken:
lt.Token = &pbs.ListToken_StartRefreshToken{
StartRefreshToken: &pbs.StartRefreshToken{
PreviousPhaseUpperBound: timestamppb.New(st.PreviousPhaseUpperBound),
PreviousDeletedIdsTime: timestamppb.New(st.PreviousDeletedIdsTime),
},
}
case *listtoken.RefreshToken:
lt.Token = &pbs.ListToken_RefreshToken{
RefreshToken: &pbs.RefreshToken{
PhaseUpperBound: timestamppb.New(st.PhaseUpperBound),
PhaseLowerBound: timestamppb.New(st.PhaseLowerBound),
PreviousDeletedIdsTime: timestamppb.New(st.PreviousDeletedIdsTime),
LastItemId: st.LastItemId,
LastItemUpdateTime: timestamppb.New(st.LastItemUpdateTime),
},
}
default:
return "", errors.New(ctx, errors.Internal, op, "unexpected list token subtype")
}
marshaled, err := proto.Marshal(lt)
if err != nil {
return "", errors.Wrap(ctx, err, op)
}
return base58.Encode(marshaled), nil
}
// ListTokenResourceToResource translates a protobuf list token resource type
// into a useable domain layer boundary resource type.
func ListTokenResourceToResource(rt pbs.ResourceType) resource.Type {
switch rt {
case pbs.ResourceType_RESOURCE_TYPE_ACCOUNT:
return resource.Account
case pbs.ResourceType_RESOURCE_TYPE_ALIAS:
return resource.Alias
case pbs.ResourceType_RESOURCE_TYPE_AUTH_METHOD:
return resource.AuthMethod
case pbs.ResourceType_RESOURCE_TYPE_AUTH_TOKEN:
return resource.AuthToken
case pbs.ResourceType_RESOURCE_TYPE_CREDENTIAL_LIBRARY:
return resource.CredentialLibrary
case pbs.ResourceType_RESOURCE_TYPE_CREDENTIAL_STORE:
return resource.CredentialStore
case pbs.ResourceType_RESOURCE_TYPE_CREDENTIAL:
return resource.Credential
case pbs.ResourceType_RESOURCE_TYPE_GROUP:
return resource.Group
case pbs.ResourceType_RESOURCE_TYPE_HOST_CATALOG:
return resource.HostCatalog
case pbs.ResourceType_RESOURCE_TYPE_HOST_SET:
return resource.HostSet
case pbs.ResourceType_RESOURCE_TYPE_HOST:
return resource.Host
case pbs.ResourceType_RESOURCE_TYPE_MANAGED_GROUP:
return resource.ManagedGroup
case pbs.ResourceType_RESOURCE_TYPE_ROLE:
return resource.Role
case pbs.ResourceType_RESOURCE_TYPE_SCOPE:
return resource.Scope
case pbs.ResourceType_RESOURCE_TYPE_SESSION_RECORDING:
return resource.SessionRecording
case pbs.ResourceType_RESOURCE_TYPE_SESSION:
return resource.Session
case pbs.ResourceType_RESOURCE_TYPE_STORAGE_BUCKET:
return resource.StorageBucket
case pbs.ResourceType_RESOURCE_TYPE_TARGET:
return resource.Target
case pbs.ResourceType_RESOURCE_TYPE_USER:
return resource.User
case pbs.ResourceType_RESOURCE_TYPE_WORKER:
return resource.Worker
case pbs.ResourceType_RESOURCE_TYPE_POLICY:
return resource.Policy
default:
return resource.Unknown
}
}