Skip to content

Commit

Permalink
Merge 7ed114c into 11ca5dc
Browse files Browse the repository at this point in the history
  • Loading branch information
efabens authored May 10, 2021
2 parents 11ca5dc + 7ed114c commit 90d99d6
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 58 deletions.
154 changes: 102 additions & 52 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,14 @@ const (
SecretValueDataKey = "secretValue"
)

const (
FileSecretType = "File"
CredentialSecretType = "Credential"
ClientSecretType = "Client"
)

var (
SecretTypes = []string{"Client", "Credential", "File"}
SecretTypes = []string{ClientSecretType, CredentialSecretType, FileSecretType}
)

type akCacheKey struct {
Expand Down Expand Up @@ -679,16 +685,25 @@ type ToznySDKV3 struct {
// Network location of the Tozny services to communicate with.
APIEndpoint string
// Tozny server defined globally unique id for this Client.
ClientID string
config e3dbClients.ClientConfig
ClientID string
CurrentIdentity TozIDSessionIdentityData
config e3dbClients.ClientConfig
}

// LoggedInIdentityData represents data about the identity session of a given user. Currently that is just realm and
// username but in the future may include tokens
type TozIDSessionIdentityData struct {
Username string `json:"username"`
Realm string `json:"realm"`
}

// ToznySDKConfig wraps parameters needed to configure a ToznySDK
type ToznySDKConfig struct {
e3dbClients.ClientConfig
AccountUsername string `json:"account_username"`
AccountPassword string `json:"account_password"`
APIEndpoint string `json:"api_url"`
TozIDSessionIdentityData `json:"toz_id_session_identity_data"`
AccountUsername string `json:"account_username"`
AccountPassword string `json:"account_password"`
APIEndpoint string `json:"api_url"`
}

// NewToznySDK returns a new instance of the ToznySDK initialized with the provided
Expand All @@ -708,6 +723,7 @@ func NewToznySDKV3(config ToznySDKConfig) (*ToznySDKV3, error) {
AccountPassword: config.AccountPassword,
APIEndpoint: config.APIEndpoint,
ClientID: config.ClientID,
CurrentIdentity: config.TozIDSessionIdentityData,
config: config.ClientConfig,
}, nil
}
Expand Down Expand Up @@ -754,6 +770,10 @@ func sdkV3FromConfig(config ToznySDKJSONConfig) (*ToznySDKV3, error) {
AccountUsername: config.AccountUsername,
AccountPassword: config.AccountPassword,
APIEndpoint: config.APIBaseURL,
TozIDSessionIdentityData: TozIDSessionIdentityData{
Username: config.Username,
Realm: config.Realm,
},
})
}

Expand Down Expand Up @@ -892,6 +912,8 @@ func GetSDKV3ForTozIDUser(login TozIDLoginRequest) (*ToznySDKV3, error) {
if err != nil {
return nil, err
}
config.Realm = realmInfo.Name
config.Username = username
return sdkV3FromConfig(config)

}
Expand Down Expand Up @@ -964,6 +986,10 @@ func (c *ToznySDKV3) StoreConfigFile(path string) error {
PrivateSigningKey: c.config.SigningKeys.Private.Material,
AccountUsername: c.AccountUsername,
AccountPassword: c.AccountPassword,
TozIDSessionIdentityData: TozIDSessionIdentityData{
Username: c.CurrentIdentity.Username,
Realm: c.CurrentIdentity.Realm,
},
}
return saveJson(path, config)
}
Expand Down Expand Up @@ -1445,7 +1471,7 @@ func (c *ToznySDKV3) CreateSecret(ctx context.Context, secret CreateSecretOption
"version": timestamp,
}
var createdRecord *pdsClient.Record
if secret.SecretType == "File" {
if secret.SecretType == FileSecretType {
createdRecord, err = c.WriteFile(ctx, recordType, plain, secret.FileName)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1708,13 +1734,13 @@ func ValidateSecret(secret CreateSecretOptions) error {
if !matched {
return errors.New("Secret name must contain 1-50 alphanumeric characters, -, or _")
}
if secret.SecretValue == "" && secret.SecretType == "Credential" {
if secret.SecretValue == "" && secret.SecretType == CredentialSecretType {
return errors.New("Value cannot be empty")
}
if secret.SecretType == "File" && strings.TrimSpace(secret.SecretName) == "" {
if secret.SecretType == FileSecretType && strings.TrimSpace(secret.SecretName) == "" {
return errors.New("File name cannot be empty")
}
if secret.SecretType == "Client" {
if secret.SecretType == ClientSecretType {
err := VerifyRawClientCredentials(secret.SecretValue)
if err != nil {
return err
Expand Down Expand Up @@ -1842,43 +1868,52 @@ func (c *ToznySDKV3) ListSecrets(ctx context.Context, options ListSecretsOptions
listRequest := storageClient.ListGroupRecordsRequest{
GroupID: group.GroupID,
}
listGroupRecords, err := c.StorageClient.GetSharedWithGroup(ctx, listRequest)
if err != nil {
return nil, err
}
// Add records shared with this group to the list of secrets the user can view.
for _, record := range listGroupRecords.ResultList {
// If this record has already been found and added to the list, skip it
_, exists := sharedSecretIDs[record.Metadata.RecordID]
if exists {
continue
}
var shared string
if group.MemberCount > 1 {
shared = "Yes"
} else {
shared = "No"
}
// find the username for secret writer if it's someone else
searchParams := identityClient.SearchRealmIdentitiesRequest{
RealmName: options.RealmName,
IdentityClientIDs: []uuid.UUID{uuid.MustParse(record.Metadata.WriterID)},
}
identities, err := c.E3dbIdentityClient.SearchRealmIdentities(ctx, searchParams)
for {
listGroupRecords, err := c.StorageClient.GetSharedWithGroup(ctx, listRequest)
if err != nil {
return nil, err
}
username := identities.SearchedIdentitiesInformation[0].RealmUsername
record.Metadata.Plain[SecretWriterUsernameMetadataKey] = username
record.Metadata.Plain[SecretSharedMetadataKey] = shared
// Decrypt the record & add to the list of secrets
recordDecrypted, err := c.DecryptTextSecret(ctx, &record)
if err != nil {
return nil, err
// Add records shared with this group to the list of secrets the user can view.
for _, record := range listGroupRecords.ResultList {
// If this record has already been found and added to the list, skip it
_, exists := sharedSecretIDs[record.Metadata.RecordID]
if exists {
continue
}
var shared string
if group.MemberCount > 1 {
shared = "Yes"
} else {
shared = "No"
}
// find the username for secret writer if it's someone else
searchParams := identityClient.SearchRealmIdentitiesRequest{
RealmName: options.RealmName,
IdentityClientIDs: []uuid.UUID{uuid.MustParse(record.Metadata.WriterID)},
}
identities, err := c.E3dbIdentityClient.SearchRealmIdentities(ctx, searchParams)
if err != nil {
return nil, err
}
username := identities.SearchedIdentitiesInformation[0].RealmUsername
record.Metadata.Plain[SecretWriterUsernameMetadataKey] = username
record.Metadata.Plain[SecretSharedMetadataKey] = shared
// Decrypt the record & add to the list of secrets
recordDecrypted, err := c.DecryptTextSecret(ctx, &record)
if err != nil {
return nil, err
}
secretDecrypted := c.MakeSecretResponse(recordDecrypted, group.GroupID.String(), username)
sharedSecretList = append(sharedSecretList, *secretDecrypted)
sharedSecretIDs[record.Metadata.RecordID] = true
}
secretDecrypted := c.MakeSecretResponse(recordDecrypted, group.GroupID.String(), username)
sharedSecretList = append(sharedSecretList, *secretDecrypted)
sharedSecretIDs[record.Metadata.RecordID] = true

if listGroupRecords.NextToken == "0" {
break
} else {
listRequest.NextToken = listGroupRecords.NextToken
}

}
}
sharedSecrets.List = sharedSecretList
Expand All @@ -1888,6 +1923,7 @@ func (c *ToznySDKV3) ListSecrets(ctx context.Context, options ListSecretsOptions

type ViewSecretOptions struct {
SecretID string
MaxSecrets int
}

// ViewSecret returns the decrypted secret with secretID
Expand All @@ -1901,21 +1937,35 @@ func (c *ToznySDKV3) ViewSecret(ctx context.Context, options ViewSecretOptions)
}
var secret *pdsClient.ListedRecord
var groupID string
var nextToken string
for _, group := range groupList.Groups {
listRequest := storageClient.ListGroupRecordsRequest{
GroupID: group.GroupID,
NextToken: nextToken,
Max: options.MaxSecrets,
}
listGroupRecords, err := c.StorageClient.GetSharedWithGroup(ctx, listRequest)
if err != nil {
return nil, err
}
for _, record := range listGroupRecords.ResultList {
if record.Metadata.RecordID == options.SecretID {
secret = &record
groupID = group.GroupID.String()
for {
listGroupRecords, err := c.StorageClient.GetSharedWithGroup(ctx, listRequest)
if err != nil {
return nil, err
}
for _, record := range listGroupRecords.ResultList {
if record.Metadata.RecordID == options.SecretID {
secret = &record
groupID = group.GroupID.String()
break
}
}
if listGroupRecords.NextToken == "0" {
break
} else {
listRequest.NextToken = listGroupRecords.NextToken
}
}
}
if secret == nil {
return nil, fmt.Errorf("the requested secret could not be found: %s", options.SecretID)
}
recordDecrypted, err := c.DecryptTextSecret(ctx, secret)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1960,7 +2010,7 @@ func (c *ToznySDKV3) MakeSecretResponse(secretRecord *pdsClient.Record, groupID
OwnerUsername: ownerUsername,
// RealmName: c.RealmName,
}
if secret.SecretType == "File" {
if secret.SecretType == FileSecretType {
secret.FileName = secretRecord.Metadata.Plain[SecretFilenameMetadataKey]
} else {
secret.SecretValue = secretRecord.Data[SecretValueDataKey]
Expand Down
1 change: 1 addition & 0 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -202,6 +202,7 @@ Interface is rapidly evolving.
type ToznySDKJSONConfig struct {
// Embed all config for v1 and v2 clients
ConfigFile
TozIDSessionIdentityData `json:"toz_id_session_identity_data"`
PublicSigningKey string `json:"public_signing_key"`
PrivateSigningKey string `json:"private_signing_key"`
AccountUsername string `json:"account_user_name"`
Expand Down
12 changes: 6 additions & 6 deletions secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ func TestCreateAndListSecrets(t *testing.T) {
}
secretReq := CreateSecretOptions{
SecretName: fmt.Sprintf("client-%s", uuid.New().String()),
SecretType: "Credential",
SecretType: CredentialSecretType,
SecretValue: uuid.New().String(),
Description: "a credential test",
RealmName: realmName,
Expand All @@ -52,7 +52,7 @@ func TestCreateAndListSecrets(t *testing.T) {
}`
secretReq2 := CreateSecretOptions{
SecretName: fmt.Sprintf("cred-%s", uuid.New().String()),
SecretType: "Client",
SecretType: ClientSecretType,
SecretValue: validClient,
Description: "a client cred test",
RealmName: realmName,
Expand Down Expand Up @@ -115,7 +115,7 @@ func TestInvalidCredSecretFails(t *testing.T) {
}`
secretReq := CreateSecretOptions{
SecretName: fmt.Sprintf("cred-%s", uuid.New().String()),
SecretType: "Client",
SecretType: ClientSecretType,
SecretValue: invalidClient,
Description: "a client cred test",
RealmName: realmName,
Expand All @@ -137,7 +137,7 @@ func TestInvalidCredSecretFails(t *testing.T) {
}`
secretReq = CreateSecretOptions{
SecretName: fmt.Sprintf("cred-%s", uuid.New().String()),
SecretType: "Client",
SecretType: ClientSecretType,
SecretValue: invalidClient,
Description: "a client cred test",
RealmName: realmName,
Expand All @@ -162,7 +162,7 @@ func TestCreateAndViewSecretSucceeds(t *testing.T) {
}
secretReq := CreateSecretOptions{
SecretName: fmt.Sprintf("client-%s", uuid.New().String()),
SecretType: "Credential",
SecretType: CredentialSecretType,
SecretValue: uuid.New().String(),
Description: "a credential test",
RealmName: realmName,
Expand Down Expand Up @@ -212,7 +212,7 @@ func TestCreateAndViewFileSecretSucceeds(t *testing.T) {
}
secretReq := CreateSecretOptions{
SecretName: fmt.Sprintf("client-%s", uuid.New().String()),
SecretType: "File",
SecretType: FileSecretType,
SecretValue: "",
Description: "a file test",
FileName: plaintextFileName,
Expand Down

0 comments on commit 90d99d6

Please sign in to comment.