mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-11-04 04:28:08 +00:00 
			
		
		
		
	* Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Adding explicit MPL license for sub-package. This directory and its subdirectories (packages) contain files licensed with the MPLv2 `LICENSE` file in this directory and are intentionally licensed separately from the BSL `LICENSE` file at the root of this repository. * Updating the license from MPL to Business Source License. Going forward, this project will be licensed under the Business Source License v1.1. Please see our blog post for more details at https://hashi.co/bsl-blog, FAQ at www.hashicorp.com/licensing-faq, and details of the license at www.hashicorp.com/bsl. * add missing license headers * Update copyright file headers to BUS-1.1 * Fix test that expected exact offset on hcl file --------- Co-authored-by: hashicorp-copywrite[bot] <110428419+hashicorp-copywrite[bot]@users.noreply.github.com> Co-authored-by: Sarah Thompson <sthompson@hashicorp.com> Co-authored-by: Brian Kassouf <bkassouf@hashicorp.com>
		
			
				
	
	
		
			238 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			238 lines
		
	
	
		
			6.7 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
// Copyright (c) HashiCorp, Inc.
 | 
						|
// SPDX-License-Identifier: BUSL-1.1
 | 
						|
 | 
						|
package rabbitmq
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
	"fmt"
 | 
						|
 | 
						|
	"github.com/fatih/structs"
 | 
						|
	"github.com/hashicorp/vault/sdk/framework"
 | 
						|
	"github.com/hashicorp/vault/sdk/helper/jsonutil"
 | 
						|
	"github.com/hashicorp/vault/sdk/logical"
 | 
						|
)
 | 
						|
 | 
						|
func pathListRoles(b *backend) *framework.Path {
 | 
						|
	return &framework.Path{
 | 
						|
		Pattern: "roles/?$",
 | 
						|
		DisplayAttrs: &framework.DisplayAttributes{
 | 
						|
			OperationPrefix: operationPrefixRabbitMQ,
 | 
						|
			OperationSuffix: "roles",
 | 
						|
		},
 | 
						|
		Callbacks: map[logical.Operation]framework.OperationFunc{
 | 
						|
			logical.ListOperation: b.pathRoleList,
 | 
						|
		},
 | 
						|
		HelpSynopsis:    pathRoleHelpSyn,
 | 
						|
		HelpDescription: pathRoleHelpDesc,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
func pathRoles(b *backend) *framework.Path {
 | 
						|
	return &framework.Path{
 | 
						|
		Pattern: "roles/" + framework.GenericNameRegex("name"),
 | 
						|
		DisplayAttrs: &framework.DisplayAttributes{
 | 
						|
			OperationPrefix: operationPrefixRabbitMQ,
 | 
						|
			OperationSuffix: "role",
 | 
						|
		},
 | 
						|
		Fields: map[string]*framework.FieldSchema{
 | 
						|
			"name": {
 | 
						|
				Type:        framework.TypeString,
 | 
						|
				Description: "Name of the role.",
 | 
						|
			},
 | 
						|
			"tags": {
 | 
						|
				Type:        framework.TypeString,
 | 
						|
				Description: "Comma-separated list of tags for this role.",
 | 
						|
			},
 | 
						|
			"vhosts": {
 | 
						|
				Type:        framework.TypeString,
 | 
						|
				Description: "A map of virtual hosts to permissions.",
 | 
						|
			},
 | 
						|
			"vhost_topics": {
 | 
						|
				Type:        framework.TypeString,
 | 
						|
				Description: "A nested map of virtual hosts and exchanges to topic permissions.",
 | 
						|
			},
 | 
						|
		},
 | 
						|
		Callbacks: map[logical.Operation]framework.OperationFunc{
 | 
						|
			logical.ReadOperation:   b.pathRoleRead,
 | 
						|
			logical.UpdateOperation: b.pathRoleUpdate,
 | 
						|
			logical.DeleteOperation: b.pathRoleDelete,
 | 
						|
		},
 | 
						|
		HelpSynopsis:    pathRoleHelpSyn,
 | 
						|
		HelpDescription: pathRoleHelpDesc,
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Reads the role configuration from the storage
 | 
						|
func (b *backend) Role(ctx context.Context, s logical.Storage, n string) (*roleEntry, error) {
 | 
						|
	entry, err := s.Get(ctx, "role/"+n)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if entry == nil {
 | 
						|
		return nil, nil
 | 
						|
	}
 | 
						|
 | 
						|
	var result roleEntry
 | 
						|
	if err := entry.DecodeJSON(&result); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return &result, nil
 | 
						|
}
 | 
						|
 | 
						|
// Deletes an existing role
 | 
						|
func (b *backend) pathRoleDelete(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
 | 
						|
	name := d.Get("name").(string)
 | 
						|
	if name == "" {
 | 
						|
		return logical.ErrorResponse("missing name"), nil
 | 
						|
	}
 | 
						|
 | 
						|
	return nil, req.Storage.Delete(ctx, "role/"+name)
 | 
						|
}
 | 
						|
 | 
						|
// Reads an existing role
 | 
						|
func (b *backend) pathRoleRead(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
 | 
						|
	name := d.Get("name").(string)
 | 
						|
	if name == "" {
 | 
						|
		return logical.ErrorResponse("missing name"), nil
 | 
						|
	}
 | 
						|
 | 
						|
	role, err := b.Role(ctx, req.Storage, name)
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if role == nil {
 | 
						|
		return nil, nil
 | 
						|
	}
 | 
						|
 | 
						|
	return &logical.Response{
 | 
						|
		Data: structs.New(role).Map(),
 | 
						|
	}, nil
 | 
						|
}
 | 
						|
 | 
						|
// Lists all the roles registered with the backend
 | 
						|
func (b *backend) pathRoleList(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
 | 
						|
	roles, err := req.Storage.List(ctx, "role/")
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return logical.ListResponse(roles), nil
 | 
						|
}
 | 
						|
 | 
						|
// Registers a new role with the backend
 | 
						|
func (b *backend) pathRoleUpdate(ctx context.Context, req *logical.Request, d *framework.FieldData) (*logical.Response, error) {
 | 
						|
	name := d.Get("name").(string)
 | 
						|
	if name == "" {
 | 
						|
		return logical.ErrorResponse("missing name"), nil
 | 
						|
	}
 | 
						|
 | 
						|
	tags := d.Get("tags").(string)
 | 
						|
	rawVHosts := d.Get("vhosts").(string)
 | 
						|
	rawVHostTopics := d.Get("vhost_topics").(string)
 | 
						|
 | 
						|
	// Either tags or VHost permissions are always required, but topic permissions are always optional.
 | 
						|
	if tags == "" && rawVHosts == "" {
 | 
						|
		return logical.ErrorResponse("both tags and vhosts not specified"), nil
 | 
						|
	}
 | 
						|
 | 
						|
	var vhosts map[string]vhostPermission
 | 
						|
	if len(rawVHosts) > 0 {
 | 
						|
		if err := jsonutil.DecodeJSON([]byte(rawVHosts), &vhosts); err != nil {
 | 
						|
			return logical.ErrorResponse(fmt.Sprintf("failed to unmarshal vhosts: %s", err)), nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	var vhostTopics map[string]map[string]vhostTopicPermission
 | 
						|
	if len(rawVHostTopics) > 0 {
 | 
						|
		if err := jsonutil.DecodeJSON([]byte(rawVHostTopics), &vhostTopics); err != nil {
 | 
						|
			return logical.ErrorResponse(fmt.Sprintf("failed to unmarshal vhost_topics: %s", err)), nil
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	// Store it
 | 
						|
	entry, err := logical.StorageEntryJSON("role/"+name, &roleEntry{
 | 
						|
		Tags:        tags,
 | 
						|
		VHosts:      vhosts,
 | 
						|
		VHostTopics: vhostTopics,
 | 
						|
	})
 | 
						|
	if err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
	if err := req.Storage.Put(ctx, entry); err != nil {
 | 
						|
		return nil, err
 | 
						|
	}
 | 
						|
 | 
						|
	return nil, nil
 | 
						|
}
 | 
						|
 | 
						|
// Role that defines the capabilities of the credentials issued against it.
 | 
						|
// Maps are used because the names of vhosts and exchanges will vary widely.
 | 
						|
// VHosts is a map with a vhost name as key and the permissions as value.
 | 
						|
// VHostTopics is a nested map with vhost name and exchange name as keys and
 | 
						|
// the topic permissions as value.
 | 
						|
type roleEntry struct {
 | 
						|
	Tags        string                                     `json:"tags" structs:"tags" mapstructure:"tags"`
 | 
						|
	VHosts      map[string]vhostPermission                 `json:"vhosts" structs:"vhosts" mapstructure:"vhosts"`
 | 
						|
	VHostTopics map[string]map[string]vhostTopicPermission `json:"vhost_topics" structs:"vhost_topics" mapstructure:"vhost_topics"`
 | 
						|
}
 | 
						|
 | 
						|
// Structure representing the permissions of a vhost
 | 
						|
type vhostPermission struct {
 | 
						|
	Configure string `json:"configure" structs:"configure" mapstructure:"configure"`
 | 
						|
	Write     string `json:"write" structs:"write" mapstructure:"write"`
 | 
						|
	Read      string `json:"read" structs:"read" mapstructure:"read"`
 | 
						|
}
 | 
						|
 | 
						|
// Structure representing the topic permissions of an exchange
 | 
						|
type vhostTopicPermission struct {
 | 
						|
	Write string `json:"write" structs:"write" mapstructure:"write"`
 | 
						|
	Read  string `json:"read" structs:"read" mapstructure:"read"`
 | 
						|
}
 | 
						|
 | 
						|
const pathRoleHelpSyn = `
 | 
						|
Manage the roles that can be created with this backend.
 | 
						|
`
 | 
						|
 | 
						|
const pathRoleHelpDesc = `
 | 
						|
This path lets you manage the roles that can be created with this backend.
 | 
						|
 | 
						|
The "tags" parameter customizes the tags used to create the role.
 | 
						|
This is a comma separated list of strings. The "vhosts" parameter customizes
 | 
						|
the virtual hosts that this user will be associated with. This is a JSON object
 | 
						|
passed as a string in the form:
 | 
						|
{
 | 
						|
	"vhostOne": {
 | 
						|
		"configure": ".*",
 | 
						|
		"write": ".*",
 | 
						|
		"read": ".*"
 | 
						|
	},
 | 
						|
	"vhostTwo": {
 | 
						|
		"configure": ".*",
 | 
						|
		"write": ".*",
 | 
						|
		"read": ".*"
 | 
						|
	}
 | 
						|
}
 | 
						|
The "vhost_topics" parameter customizes the topic permissions that this user
 | 
						|
will be granted. This is a JSON object passed as a string in the form:
 | 
						|
{
 | 
						|
	"vhostOne": {
 | 
						|
		"exchangeOneOne": {
 | 
						|
			"write": ".*",
 | 
						|
			"read": ".*"
 | 
						|
		},
 | 
						|
		"exchangeOneTwo": {
 | 
						|
			"write": ".*",
 | 
						|
			"read": ".*"
 | 
						|
		}
 | 
						|
	},
 | 
						|
	"vhostTwo": {
 | 
						|
		"exchangeTwoOne": {
 | 
						|
			"write": ".*",
 | 
						|
			"read": ".*"
 | 
						|
		}
 | 
						|
	}
 | 
						|
}
 | 
						|
`
 |