Skip to content

Commit

Permalink
fix naming, error messages
Browse files Browse the repository at this point in the history
  • Loading branch information
carrala committed May 20, 2021
1 parent 41e5256 commit 3e0126c
Show file tree
Hide file tree
Showing 2 changed files with 93 additions and 43 deletions.
38 changes: 21 additions & 17 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2122,16 +2122,16 @@ func (c *ToznySDKV3) MakeSecretResponse(secretRecord *pdsClient.Record, groupID
return secret
}

type ShareSecretInfo struct {
type ShareSecretOptions struct {
SecretName string
SecretType string
UsernameToAddWithPermissions map[string][]string
}

// ShareSecretWithUsername shares all versions of a specified secret with the user with UsernameToAdd
func (c *ToznySDKV3) ShareSecretWithUsername(ctx context.Context, params ShareSecretInfo) error {
if len(params.UsernameToAddWithPermissions) == 0 {
return fmt.Errorf("ShareSecretWithUsername: Username to add must be provided.")
func (c *ToznySDKV3) ShareSecretWithUsername(ctx context.Context, options ShareSecretOptions) error {
if len(options.UsernameToAddWithPermissions) != 1 {
return fmt.Errorf("ShareSecretWithUsername: One username to add must be provided.")
}
var clientID uuid.UUID
sharingMatrix := make(map[uuid.UUID][]string)
Expand All @@ -2142,7 +2142,7 @@ func (c *ToznySDKV3) ShareSecretWithUsername(ctx context.Context, params ShareSe
// Add default permissions for the calling client to the sharing matrix
// If the calling client & permissions were included in UsernameToAddWithPermissions, these will be overwritten
sharingMatrix[ownerClientID] = []string{storageClient.ShareContentGroupCapability, storageClient.ReadContentGroupCapability}
for username, permissions := range params.UsernameToAddWithPermissions {
for username, permissions := range options.UsernameToAddWithPermissions {
// Find the clientID for the username to add
searchParams := identityClient.SearchRealmIdentitiesRequest{
RealmName: c.CurrentIdentity.Realm,
Expand All @@ -2153,55 +2153,59 @@ func (c *ToznySDKV3) ShareSecretWithUsername(ctx context.Context, params ShareSe
return err
}
if len(identities.SearchedIdentitiesInformation) < 1 {
return fmt.Errorf("ShareSecretWithUser: no identity found with username %s", username)
return fmt.Errorf("ShareSecretWithUser: no identity found within realm %s with username %s", c.CurrentIdentity.Realm, username)
}
clientID = identities.SearchedIdentitiesInformation[0].ClientID
// Add client to the sharing matrix
sharingMatrix[clientID] = permissions
}
// If user tries to share secret with self, return without failure
if clientID == ownerClientID {
return nil
}
// Find or create the group for sharing with UsernameToAdd
namespaceOptions := NamespaceOptions{
RealmName: c.CurrentIdentity.Realm,
Namespace: fmt.Sprintf("%s.%s.%s.%s", c.StorageClient.ClientID, clientID, params.SecretName, params.SecretType),
Namespace: fmt.Sprintf("%s.%s.%s.%s", c.StorageClient.ClientID, clientID, options.SecretName, options.SecretType),
SharingMatrix: sharingMatrix,
}
group, err := c.GetOrCreateNamespace(ctx, namespaceOptions)
if err != nil {
return err
}
// Share record type with group
recordType := fmt.Sprintf("tozny.secret.%s.%s.%s", SecretUUID, params.SecretType, params.SecretName)
recordType := fmt.Sprintf("tozny.secret.%s.%s.%s", SecretUUID, options.SecretType, options.SecretName)
err = c.ShareRecordWithGroup(ctx, recordType, group)
if err != nil {
return err
}
return nil
}

type UnshareSecretInfo struct {
type UnshareSecretOptions struct {
SecretName string
SecretType string
UsernameToRevoke string
}

// UnshareSecretFromUsername revokes read access to secrets of provided name & type for this specific user
// Calling client must be the owner of the secret for this to succeed.
func (c *ToznySDKV3) UnshareSecretFromUsername(ctx context.Context, params UnshareSecretInfo) error {
if params.UsernameToRevoke == "" {
func (c *ToznySDKV3) UnshareSecretFromUsername(ctx context.Context, options UnshareSecretOptions) error {
if options.UsernameToRevoke == "" {
return fmt.Errorf("UnshareSecretFromUsername: Username to revoke must be provided")
}
// find the clientID for the username
searchParams := identityClient.SearchRealmIdentitiesRequest{
RealmName: c.CurrentIdentity.Realm,
IdentityUsernames: []string{params.UsernameToRevoke},
IdentityUsernames: []string{options.UsernameToRevoke},
}
identities, err := c.E3dbIdentityClient.SearchRealmIdentities(ctx, searchParams)
if err != nil {
return err
}
// Username doesn't match an identity, so return an error
if len(identities.SearchedIdentitiesInformation) < 1 {
return fmt.Errorf("UnshareSecretFromUsername: no identity found within realm with username %s", params.UsernameToRevoke)
return fmt.Errorf("UnshareSecretFromUsername: no identity found within realm %s with username %s", c.CurrentIdentity.Realm, options.UsernameToRevoke)
}
// Find the sharing group
revokeClientID := identities.SearchedIdentitiesInformation[0].ClientID
Expand All @@ -2213,21 +2217,21 @@ func (c *ToznySDKV3) UnshareSecretFromUsername(ctx context.Context, params Unsha
if revokeClientID == ownerClientID {
return fmt.Errorf("UnshareSecretFromUsername: Cannot unshare secret from self")
}
groupName := fmt.Sprintf("tozny.secret.%s.%s.%s.%s.%s", c.CurrentIdentity.Realm, ownerClientID, revokeClientID, params.SecretName, params.SecretType)
groupName := fmt.Sprintf("tozny.secret.%s.%s.%s.%s.%s", c.CurrentIdentity.Realm, ownerClientID, revokeClientID, options.SecretName, options.SecretType)
listRequest := storageClient.ListGroupsRequest{
GroupNames: []string{groupName},
}
listGroupResponse, err := c.StorageClient.ListGroups(ctx, listRequest)
if err != nil {
return err
}
// Group does not exist, so secret isn't shared with this identity and unsharing fails.
// Group does not exist, so secret isn't shared with this identity and unsharing doesn't need to happen.
if len(listGroupResponse.Groups) < 1 {
return fmt.Errorf("UnshareSecretWithUsername: Sharing group does not exist, so unsharing failed")
return fmt.Errorf("UnshareSecretFromUsername: sharing group does not exist")
}
// Unshare secret's record type from the group
groupID := listGroupResponse.Groups[0].GroupID
recordType := fmt.Sprintf("tozny.secret.%s.%s.%s", SecretUUID, params.SecretType, params.SecretName)
recordType := fmt.Sprintf("tozny.secret.%s.%s.%s", SecretUUID, options.SecretType, options.SecretName)
recordRemoveShareRequest := storageClient.RemoveRecordSharedWithGroupRequest{
GroupID: groupID,
RecordType: recordType,
Expand Down
98 changes: 72 additions & 26 deletions secrets_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ func TestShareSecretByUsernameSucceeds(t *testing.T) {
t.Fatal("Expected an error since secret isn't shared")
}
// id 1 shares the secret with id 2
shareOptions := ShareSecretInfo{
shareOptions := ShareSecretOptions{
SecretName: secretCreated.SecretName,
SecretType: secretCreated.SecretType,
UsernameToAddWithPermissions: map[string][]string{
Expand All @@ -292,7 +292,7 @@ func TestShareSecretByUsernameSucceeds(t *testing.T) {
t.Fatalf("SecretValue doesn't match. Created: %s Viewed: %s", secretCreated.Record.Data["secretValue"], secretView.Record.Data["secretValue"])
}
// id 1 unshares secret from id 2
unshareOptions := UnshareSecretInfo{
unshareOptions := UnshareSecretOptions{
SecretName: secretCreated.SecretName,
SecretType: secretCreated.SecretType,
UsernameToRevoke: username,
Expand Down Expand Up @@ -329,7 +329,7 @@ func TestShareSecretInvalidOptionsFails(t *testing.T) {
t.Fatalf("Error viewing shared secret: %+v", err)
}
// share secret with a username that doesn't exist
shareOptions := ShareSecretInfo{
shareOptions := ShareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToAddWithPermissions: map[string][]string{
Expand All @@ -341,7 +341,7 @@ func TestShareSecretInvalidOptionsFails(t *testing.T) {
t.Fatal("Should error since username doesn't exist\n")
}
// share secret with no one
shareOptions = ShareSecretInfo{
shareOptions = ShareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToAddWithPermissions: map[string][]string{},
Expand All @@ -350,6 +350,19 @@ func TestShareSecretInvalidOptionsFails(t *testing.T) {
if err == nil {
t.Fatal("Should error since no usernames were included to share with\n")
}
// share secret with two users
shareOptions = ShareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToAddWithPermissions: map[string][]string{
username2: {"SHARE_CONTENT", "READ_CONTENT"},
"invalid-username": {"SHARE_CONTENT", "READ_CONTENT"},
},
}
err = sdk.ShareSecretWithUsername(testCtx, shareOptions)
if err == nil {
t.Fatal("Should error since more than one uername was provided\n")
}
}

func TestUnshareSecretInvalidOptionsFails(t *testing.T) {
Expand All @@ -372,7 +385,7 @@ func TestUnshareSecretInvalidOptionsFails(t *testing.T) {
if err != nil {
t.Fatalf("Error viewing shared secret: %+v", err)
}
shareOptions := ShareSecretInfo{
shareOptions := ShareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToAddWithPermissions: map[string][]string{
Expand All @@ -384,7 +397,7 @@ func TestUnshareSecretInvalidOptionsFails(t *testing.T) {
t.Fatalf("Error sharing with username: Err: %+v\n", err)
}
// unshare secret with no username provided
unshareOptions := UnshareSecretInfo{
unshareOptions := UnshareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
}
Expand All @@ -393,7 +406,7 @@ func TestUnshareSecretInvalidOptionsFails(t *testing.T) {
t.Fatal("Should error since username doesn't exist\n")
}
// unshare secret from secret creator
unshareOptions = UnshareSecretInfo{
unshareOptions = UnshareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToRevoke: username,
Expand All @@ -405,6 +418,42 @@ func TestUnshareSecretInvalidOptionsFails(t *testing.T) {
}

func TestUnshareSecretFromOwnerFails(t *testing.T) {
// login id 1
request := TozIDLoginRequest{
Username: username2,
Password: password,
RealmName: realmName,
APIBaseURL: baseURL,
LoginHandler: mfaHandler,
}
sdk, err := GetSDKV3ForTozIDUser(request)
if err != nil {
t.Fatalf("Could not log in %+v", err)
}
secretReq := CreateSecretOptions{
SecretName: fmt.Sprintf("client-%s", uuid.New().String()),
SecretType: CredentialSecretType,
SecretValue: uuid.New().String(),
Description: "a credential test",
RealmName: realmName,
}
secret, err := sdk.CreateSecret(testCtx, secretReq)
if err != nil {
t.Fatalf("Could not create secret: Req: %+v Err: %+v", secretReq, err)
}
// Try to unshare the secret from the calling client
unshareOptions := UnshareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToRevoke: username2,
}
err = sdk.UnshareSecretFromUsername(testCtx, unshareOptions)
if err == nil {
t.Fatal("Should error since username is the secret owner\n")
}
}

func TestUnshareTwiceSucceeds(t *testing.T) {
// login id 1
request := TozIDLoginRequest{
Username: username2,
Expand Down Expand Up @@ -440,17 +489,8 @@ func TestUnshareSecretFromOwnerFails(t *testing.T) {
if err != nil {
t.Fatalf("Could not create secret: Req: %+v Err: %+v", secretReq, err)
}
// Try to unshare the secret from the calling client
unshareOptions := UnshareSecretInfo{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToRevoke: username2,
}
err = sdk.UnshareSecretFromUsername(testCtx, unshareOptions)
if err == nil {
t.Fatal("Should error since username is the secret owner\n")
}
shareOptions := ShareSecretInfo{
// id 1 shares the secret with id 2
shareOptions := ShareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToAddWithPermissions: map[string][]string{
Expand All @@ -461,23 +501,29 @@ func TestUnshareSecretFromOwnerFails(t *testing.T) {
if err != nil {
t.Fatalf("Error sharing with username: Err: %+v\n", err)
}
// id 2 tries to view secret -- expect success
viewOptions := ViewSecretOptions{
SecretID: uuid.MustParse(secret.SecretID.String()),
SecretID: uuid.MustParse(secret1ID),
MaxSecrets: 1000,
}
_, err = sdk.ViewSecret(testCtx, viewOptions)
_, err = sdk2.ViewSecret(testCtx, viewOptions)
if err != nil {
t.Fatalf("Error viewing shared secret: %+v", err)
}
// Viewer of secret tries to unshare the secret from the owner
unshareOptions = UnshareSecretInfo{
// id 1 unshares secret from id 2
unshareOptions := UnshareSecretOptions{
SecretName: secret.SecretName,
SecretType: secret.SecretType,
UsernameToRevoke: username2,
UsernameToRevoke: username,
}
err = sdk2.UnshareSecretFromUsername(testCtx, unshareOptions)
if err == nil {
t.Fatal("Should error since username is the secret owner\n")
err = sdk.UnshareSecretFromUsername(testCtx, unshareOptions)
if err != nil {
t.Fatalf("Unshare secret failed %+v", err)
}
// id 1 unshares secret from id 2 again -- should succeed since the group exists
err = sdk.UnshareSecretFromUsername(testCtx, unshareOptions)
if err != nil {
t.Fatalf("Unshare secret again failed %+v", err)
}
}

Expand Down

0 comments on commit 3e0126c

Please sign in to comment.