lib/clouds/mock_token_creator.go (136 lines of code) (raw):
// Copyright 2019 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package clouds
import (
"context"
"fmt"
"time"
"github.com/GoogleCloudPlatform/healthcare-federated-access-services/lib/storage" /* copybara-comment: storage */
cpb "github.com/GoogleCloudPlatform/healthcare-federated-access-services/proto/common/v1" /* copybara-comment: go_proto */
)
type MockTokenCreatorEntry struct {
AccountID string
TokenID string
TTL time.Duration
MaxTTL time.Duration
NumKeys int
Params ResourceTokenCreationParams
IssuedAt int64
Expires int64
Token string
}
// MockTokenCreator provides a token creator implementation for testing.
type MockTokenCreator struct {
includeParams bool
calls []MockTokenCreatorEntry
tokens map[string][]*cpb.TokenMetadata
tokID int64
}
// NewMockTokenCreator creates a mock ResourceTokenCreator.
func NewMockTokenCreator(includeParams bool) *MockTokenCreator {
return &MockTokenCreator{
includeParams: includeParams,
calls: []MockTokenCreatorEntry{},
tokens: make(map[string][]*cpb.TokenMetadata),
tokID: 0,
}
}
// RegisterAccountProject registers account hosting project in key garbage collector.
func (m *MockTokenCreator) RegisterAccountProject(project string, tx storage.Tx) error {
return nil
}
// UnregisterAccountProject (eventually) removes a project from the active state, and allows cleanup work to be performed.
func (m *MockTokenCreator) UnregisterAccountProject(project string, tx storage.Tx) error {
return nil
}
// UpdateSettings alters resource management settings.
func (m *MockTokenCreator) UpdateSettings(maxRequestedTTL time.Duration, keysPerAccount int, tx storage.Tx) error {
return nil
}
// MintTokenWithTTL returns an account and a resource token for resource accessing.
func (m *MockTokenCreator) MintTokenWithTTL(ctx context.Context, id string, ttl, maxTTL time.Duration, numKeys int, params *ResourceTokenCreationParams) (*ResourceTokenResult, error) {
m.tokID++
tokenID := fmt.Sprintf("%d", m.tokID)
entry := MockTokenCreatorEntry{
AccountID: id,
TokenID: tokenID,
TTL: ttl,
MaxTTL: maxTTL,
NumKeys: numKeys,
IssuedAt: m.tokID,
Expires: m.tokID + 1000,
Token: "token_" + tokenID,
}
if m.includeParams {
entry.Params = *params
}
tokenUser := testTokenUser(params.AccountProject, id)
list, ok := m.tokens[tokenUser]
if !ok {
list = []*cpb.TokenMetadata{}
}
m.tokens[tokenUser] = append(list, &cpb.TokenMetadata{
Name: entry.TokenID,
IssuedAt: fmt.Sprintf("%d", entry.IssuedAt),
Expires: fmt.Sprintf("%d", entry.Expires),
})
m.calls = append(m.calls, entry)
if ttl > maxTTL {
return nil, fmt.Errorf("TTL of %v exceeds max TTL of %v", ttl, maxTTL)
}
return &ResourceTokenResult{
Account: "acct",
Token: entry.Token,
Format: "base64",
}, nil
}
func testTokenUser(project, id string) string {
return project + "/" + id
}
// GetTokenMetadata returns an access token based on its name.
func (m *MockTokenCreator) GetTokenMetadata(ctx context.Context, project, id, name string) (*cpb.TokenMetadata, error) {
list, err := m.ListTokenMetadata(ctx, project, id)
if err != nil {
return nil, fmt.Errorf("getting token: %v", err)
}
for _, meta := range list {
if meta.Name == name {
return meta, nil
}
}
return nil, fmt.Errorf("token %q not found", name)
}
// ListTokenMetadata returns a list of outstanding access tokens.
func (m *MockTokenCreator) ListTokenMetadata(ctx context.Context, project, id string) ([]*cpb.TokenMetadata, error) {
tokenUser := testTokenUser(project, id)
list, ok := m.tokens[tokenUser]
if !ok {
return []*cpb.TokenMetadata{}, nil
}
return list, nil
}
// DeleteTokens removes tokens belonging to 'id' with given names.
// If 'names' is empty, delete all tokens belonging to 'id'.
func (m *MockTokenCreator) DeleteTokens(ctx context.Context, project, id string, names []string) error {
tokenUser := testTokenUser(project, id)
if len(names) == 0 {
delete(m.tokens, tokenUser)
return nil
}
list, ok := m.tokens[tokenUser]
if !ok {
return fmt.Errorf("namespace %q empty (cannot delete %d entries)", tokenUser, len(names))
}
for _, name := range names {
found := false
for i, entry := range list {
if entry.Name == name {
if len(list) == 1 {
list = []*cpb.TokenMetadata{}
delete(m.tokens, tokenUser)
} else {
list = append(list[:i-1], list[i+1:]...)
}
found = true
break
}
}
if !found {
return fmt.Errorf("namespace %q token %q not found", tokenUser, name)
}
}
return nil
}
func (m *MockTokenCreator) Calls() []MockTokenCreatorEntry {
c := m.calls
m.calls = []MockTokenCreatorEntry{}
return c
}