Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(permissionmap): fixes our permission map to actually run the redi… #1490

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 0 additions & 12 deletions internal/jimm/applicationoffer.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,10 +217,6 @@ func (j *JIMM) GetApplicationOfferConsumeDetails(ctx context.Context, user *open
ctx,
&offer.Model.Controller,
names.ModelTag{},
permission{
resource: names.NewApplicationOfferTag(offer.UUID).String(),
relation: accessLevel,
},
)
if err != nil {
return errors.E(op, err)
Expand Down Expand Up @@ -366,10 +362,6 @@ func (j *JIMM) GetApplicationOffer(ctx context.Context, user *openfga.User, offe
ctx,
&offer.Model.Controller,
names.ModelTag{},
permission{
resource: names.NewApplicationOfferTag(offer.UUID).String(),
relation: accessLevel,
},
)
if err != nil {
return nil, errors.E(op, err)
Expand Down Expand Up @@ -706,10 +698,6 @@ func (j *JIMM) doApplicationOfferAdmin(ctx context.Context, user *openfga.User,
ctx,
&offer.Model.Controller,
names.ModelTag{},
permission{
resource: names.NewApplicationOfferTag(offer.UUID).String(),
relation: string(jujuparams.OfferAdminAccess),
},
)
if err != nil {
return errors.E(op, err)
Expand Down
21 changes: 6 additions & 15 deletions internal/jimm/jimm.go
Original file line number Diff line number Diff line change
Expand Up @@ -306,27 +306,18 @@ func (j *JIMM) GetCredentialStore() credentials.CredentialStore {
return j.CredentialStore
}

type permission struct {
resource string
relation string
}

// dial dials the controller and model specified by the given Controller
// and ModelTag. If no Dialer has been configured then an error with a
// code of CodeConnectionFailed will be returned.
func (j *JIMM) dial(ctx context.Context, ctl *dbmodel.Controller, modelTag names.ModelTag, permissons ...permission) (API, error) {
//
// It utilises a nil permission map to allow the controller to return
// the expected permissions back to the caller and then redials
// the controller with the correct permissions.
func (j *JIMM) dial(ctx context.Context, ctl *dbmodel.Controller, modelTag names.ModelTag) (API, error) {
if j == nil || j.Dialer == nil {
return nil, errors.E(errors.CodeConnectionFailed, "no dialer configured")
}
var permissionMap map[string]string
if len(permissons) > 0 {
permissionMap = make(map[string]string, len(permissons))
for _, p := range permissons {
permissionMap[p.resource] = p.relation
}
}

return j.Dialer.Dial(ctx, ctl, modelTag, permissionMap)
return j.Dialer.Dial(ctx, ctl, modelTag, nil)
}

// A Dialer provides a connection to a controller.
Expand Down
5 changes: 0 additions & 5 deletions internal/jimm/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import (
"strings"
"time"

jujupermission "github.com/juju/juju/core/permission"
jujuparams "github.com/juju/juju/rpc/params"
"github.com/juju/juju/state"
"github.com/juju/names/v5"
Expand Down Expand Up @@ -469,10 +468,6 @@ func (b *modelBuilder) CreateControllerModel() *modelBuilder {
b.ctx,
b.controller,
names.ModelTag{},
permission{
resource: b.cloud.ResourceTag().String(),
relation: string(jujupermission.AddModelAccess),
},
)
if err != nil {
b.err = errors.E(err)
Expand Down
6 changes: 3 additions & 3 deletions internal/jujuclient/allwatcher.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (
// WatchAllModels initialises a new AllModelWatcher. On success the watcher
// ID is returned. This uses the WatchAllModels method on the Controller
// facade.
func (c Connection) WatchAllModels(ctx context.Context) (string, error) {
func (c *Connection) WatchAllModels(ctx context.Context) (string, error) {
const op = errors.Op("jujuclient.WatchAllModels")
var resp jujuparams.SummaryWatcherID
if err := c.CallHighestFacadeVersion(ctx, "Controller", []int{11, 7}, "", "WatchAllModels", nil, &resp); err != nil {
Expand All @@ -26,7 +26,7 @@ func (c Connection) WatchAllModels(ctx context.Context) (string, error) {
// AllModelWatcherNext receives the next set of results from the all-model
// watcher with the given id. This uses the Next method on the
// AllModelWatcher facade.
func (c Connection) AllModelWatcherNext(ctx context.Context, id string) ([]jujuparams.Delta, error) {
func (c *Connection) AllModelWatcherNext(ctx context.Context, id string) ([]jujuparams.Delta, error) {
const op = errors.Op("jujuclient.AllModelWatcherNext")
var resp jujuparams.AllWatcherNextResults
if err := c.CallHighestFacadeVersion(ctx, "AllModelWatcher", []int{4, 2}, id, "Next", nil, &resp); err != nil {
Expand All @@ -37,7 +37,7 @@ func (c Connection) AllModelWatcherNext(ctx context.Context, id string) ([]jujup

// AllModelWatcherStop stops the all-model watcher with the given id. This
// uses the Stop method on the AllModelWatcher facade.
func (c Connection) AllModelWatcherStop(ctx context.Context, id string) error {
func (c *Connection) AllModelWatcherStop(ctx context.Context, id string) error {
const op = errors.Op("jujuclient.AllModelWatcherStop")
if err := c.CallHighestFacadeVersion(ctx, "AllModelWatcher", []int{4, 2}, id, "Stop", nil, nil); err != nil {
return errors.E(op, jujuerrors.Cause(err))
Expand Down
16 changes: 8 additions & 8 deletions internal/jujuclient/applicationoffers.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (

// Offer creates a new ApplicationOffer on the controller. Offer uses the
// Offer procedure on the ApplicationOffers facade.
func (c Connection) Offer(ctx context.Context, offerURL crossmodel.OfferURL, offer jujuparams.AddApplicationOffer) error {
func (c *Connection) Offer(ctx context.Context, offerURL crossmodel.OfferURL, offer jujuparams.AddApplicationOffer) error {
const op = errors.Op("jujuclient.Offer")
args := jujuparams.AddApplicationOffers{
Offers: []jujuparams.AddApplicationOffer{offer},
Expand Down Expand Up @@ -64,7 +64,7 @@ func (c Connection) Offer(ctx context.Context, offerURL crossmodel.OfferURL, off
// ListApplicationOffers lists ApplicationOffers on the controller matching
// the given filters. ListApplicationOffers uses the ListApplicationOffers
// procedure on the ApplicationOffers facade.
func (c Connection) ListApplicationOffers(ctx context.Context, filters []jujuparams.OfferFilter) ([]jujuparams.ApplicationOfferAdminDetailsV5, error) {
func (c *Connection) ListApplicationOffers(ctx context.Context, filters []jujuparams.OfferFilter) ([]jujuparams.ApplicationOfferAdminDetailsV5, error) {
const op = errors.Op("jujuclient.ListApplicationOffers")
args := jujuparams.OfferFilters{
Filters: filters,
Expand All @@ -81,7 +81,7 @@ func (c Connection) ListApplicationOffers(ctx context.Context, filters []jujupar
// FindApplicationOffers finds ApplicationOffers on the controller matching
// the given filters. FindApplicationOffers uses the FindApplicationOffers
// procedure on the ApplicationOffers facade.
func (c Connection) FindApplicationOffers(ctx context.Context, filters []jujuparams.OfferFilter) ([]jujuparams.ApplicationOfferAdminDetailsV5, error) {
func (c *Connection) FindApplicationOffers(ctx context.Context, filters []jujuparams.OfferFilter) ([]jujuparams.ApplicationOfferAdminDetailsV5, error) {
const op = errors.Op("jujuclient.FindApplicationOffers")
args := jujuparams.OfferFilters{
Filters: filters,
Expand All @@ -100,7 +100,7 @@ func (c Connection) FindApplicationOffers(ctx context.Context, filters []jujupar
// OfferURL the rest of the structure will be filled in by the API request.
// GetApplicationOffer uses the ApplicationOffers procedure on the
// ApplicationOffers facade.
func (c Connection) GetApplicationOffer(ctx context.Context, info *jujuparams.ApplicationOfferAdminDetailsV5) error {
func (c *Connection) GetApplicationOffer(ctx context.Context, info *jujuparams.ApplicationOfferAdminDetailsV5) error {
const op = errors.Op("jujuclient.GetApplicationOffer")
args := jujuparams.OfferURLs{
OfferURLs: []string{info.OfferURL},
Expand All @@ -123,7 +123,7 @@ func (c Connection) GetApplicationOffer(ctx context.Context, info *jujuparams.Ap
// GrantApplicationOfferAccess grants the specified permission to the
// given user on the given application offer. GrantApplicationOfferAccess
// uses the ModifyOfferAccess procedure on the ApplicationOffers facade..
func (c Connection) GrantApplicationOfferAccess(ctx context.Context, offerURL string, user names.UserTag, access jujuparams.OfferAccessPermission) error {
func (c *Connection) GrantApplicationOfferAccess(ctx context.Context, offerURL string, user names.UserTag, access jujuparams.OfferAccessPermission) error {
const op = errors.Op("jujuclient.GrantApplicationOfferAccess")
args := jujuparams.ModifyOfferAccessRequest{
Changes: []jujuparams.ModifyOfferAccess{{
Expand All @@ -150,7 +150,7 @@ func (c Connection) GrantApplicationOfferAccess(ctx context.Context, offerURL st
// RevokeApplicationOfferAccess revokes the specified permission from the
// given user on the given application offer. RevokeApplicationOfferAccess
// uses the ModifyOfferAccess procedure on the ApplicationOffers facade.
func (c Connection) RevokeApplicationOfferAccess(ctx context.Context, offerURL string, user names.UserTag, access jujuparams.OfferAccessPermission) error {
func (c *Connection) RevokeApplicationOfferAccess(ctx context.Context, offerURL string, user names.UserTag, access jujuparams.OfferAccessPermission) error {
const op = errors.Op("jujuclient.RevokeApplicationOfferAccess")
args := jujuparams.ModifyOfferAccessRequest{
Changes: []jujuparams.ModifyOfferAccess{{
Expand All @@ -177,7 +177,7 @@ func (c Connection) RevokeApplicationOfferAccess(ctx context.Context, offerURL s
// DestroyApplicationOffer destroys the given application offer.
// DestroyApplicationOffer uses the DestroyOffers procedure
// from the ApplicationOffers facade.
func (c Connection) DestroyApplicationOffer(ctx context.Context, offer string, force bool) error {
func (c *Connection) DestroyApplicationOffer(ctx context.Context, offer string, force bool) error {
const op = errors.Op("jujuclient.DestroyApplicationOffer")
args := jujuparams.DestroyApplicationOffers{
OfferURLs: []string{offer},
Expand All @@ -202,7 +202,7 @@ func (c Connection) DestroyApplicationOffer(ctx context.Context, offer string, f
// must include an Offer.OfferURL and the rest of the structure will be
// filled in by the API call. GetApplicationOfferConsumeDetails uses the
// GetConsumeDetails procedure on the ApplicationOffers facade.
func (c Connection) GetApplicationOfferConsumeDetails(ctx context.Context, user names.UserTag, info *jujuparams.ConsumeOfferDetails, v bakery.Version) error {
func (c *Connection) GetApplicationOfferConsumeDetails(ctx context.Context, user names.UserTag, info *jujuparams.ConsumeOfferDetails, v bakery.Version) error {
const op = errors.Op("jujuclient.GetApplicationOfferConsumeDetails")
args := jujuparams.ConsumeOfferDetailsArg{
OfferURLs: jujuparams.OfferURLs{
Expand Down
2 changes: 1 addition & 1 deletion internal/jujuclient/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

// Status returns the status of the juju model.
func (c Connection) Status(ctx context.Context, patterns []string) (*jujuparams.FullStatus, error) {
func (c *Connection) Status(ctx context.Context, patterns []string) (*jujuparams.FullStatus, error) {
const op = errors.Op("jujuclient.Status")

p := jujuparams.StatusParams{
Expand Down
24 changes: 12 additions & 12 deletions internal/jujuclient/cloud.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import (
// SupportsCheckCredentialModels reports whether the controller supports
// the Cloud.CheckCredentialsModels, Cloud.RevokeCredentialsCheckModels,
// and Cloud.UpdateCredentialsCheckModels methods.
func (c Connection) SupportsCheckCredentialModels() bool {
func (c *Connection) SupportsCheckCredentialModels() bool {
return c.hasFacadeVersion("Cloud", 3) || c.hasFacadeVersion("Cloud", 7)
}

Expand All @@ -26,7 +26,7 @@ func (c Connection) SupportsCheckCredentialModels() bool {
// credential. This method uses the CheckCredentialsModel procedure on
// the Cloud. Any error that represents a Juju API
// failure will be of type *APIError.
func (c Connection) CheckCredentialModels(ctx context.Context, cred jujuparams.TaggedCredential) ([]jujuparams.UpdateCredentialModelResult, error) {
func (c *Connection) CheckCredentialModels(ctx context.Context, cred jujuparams.TaggedCredential) ([]jujuparams.UpdateCredentialModelResult, error) {
const op = errors.Op("jujuclient.CheckCredentialModels")
in := jujuparams.TaggedCredentials{
Credentials: []jujuparams.TaggedCredential{cred},
Expand Down Expand Up @@ -57,7 +57,7 @@ func (c Connection) CheckCredentialModels(ctx context.Context, cred jujuparams.T
//
// Any error that represents a Juju API failure will be of type
// *APIError.
func (c Connection) UpdateCredential(ctx context.Context, cred jujuparams.TaggedCredential) ([]jujuparams.UpdateCredentialModelResult, error) {
func (c *Connection) UpdateCredential(ctx context.Context, cred jujuparams.TaggedCredential) ([]jujuparams.UpdateCredentialModelResult, error) {
const op = errors.Op("jujuclient.UpdateCredential")
creds := jujuparams.TaggedCredentials{
Credentials: []jujuparams.TaggedCredential{cred},
Expand Down Expand Up @@ -98,7 +98,7 @@ func (c Connection) UpdateCredential(ctx context.Context, cred jujuparams.Tagged
//
// Any error that represents a Juju API failure will be of type
// *APIError.
func (c Connection) RevokeCredential(ctx context.Context, cred names.CloudCredentialTag) error {
func (c *Connection) RevokeCredential(ctx context.Context, cred names.CloudCredentialTag) error {
const op = errors.Op("jujuclient.RevokeCredential")
out := jujuparams.ErrorResults{
Results: make([]jujuparams.ErrorResult, 1),
Expand Down Expand Up @@ -131,7 +131,7 @@ func (c Connection) RevokeCredential(ctx context.Context, cred names.CloudCreden

// Cloud retrieves information about the given cloud. Cloud uses the
// Cloud procedure on the Cloud facade.
func (c Connection) Cloud(ctx context.Context, tag names.CloudTag, cloud *jujuparams.Cloud) error {
func (c *Connection) Cloud(ctx context.Context, tag names.CloudTag, cloud *jujuparams.Cloud) error {
const op = errors.Op("jujuclient.Cloud")
args := jujuparams.Entities{
Entities: []jujuparams.Entity{{
Expand All @@ -154,7 +154,7 @@ func (c Connection) Cloud(ctx context.Context, tag names.CloudTag, cloud *jujupa

// Clouds retrieves information about all available clouds. Clouds uses the
// Clouds procedure on the Cloud facade.
func (c Connection) Clouds(ctx context.Context) (map[names.CloudTag]jujuparams.Cloud, error) {
func (c *Connection) Clouds(ctx context.Context) (map[names.CloudTag]jujuparams.Cloud, error) {
const op = errors.Op("jujuclient.Clouds")
var resp jujuparams.CloudsResult
if err := c.CallHighestFacadeVersion(ctx, "Cloud", []int{7, 1}, "", "Clouds", nil, &resp); err != nil {
Expand All @@ -175,7 +175,7 @@ func (c Connection) Clouds(ctx context.Context) (map[names.CloudTag]jujuparams.C

// AddCloud adds the given cloud to a controller with the given name.
// AddCloud uses the AddCloud procedure on the Cloud facade.
func (c Connection) AddCloud(ctx context.Context, tag names.CloudTag, cloud jujuparams.Cloud, force bool) error {
func (c *Connection) AddCloud(ctx context.Context, tag names.CloudTag, cloud jujuparams.Cloud, force bool) error {
const op = errors.Op("jujuclient.AddCloud")
args := jujuparams.AddCloudArgs{
Cloud: cloud,
Expand All @@ -190,7 +190,7 @@ func (c Connection) AddCloud(ctx context.Context, tag names.CloudTag, cloud juju

// RemoveCloud removes the given cloud from the controller. RemoveCloud
// uses the RemoveClouds procedure on the Cloud facade.
func (c Connection) RemoveCloud(ctx context.Context, tag names.CloudTag) error {
func (c *Connection) RemoveCloud(ctx context.Context, tag names.CloudTag) error {
const op = errors.Op("jujuclient.RemoveCloud")
args := jujuparams.Entities{
Entities: []jujuparams.Entity{{
Expand All @@ -212,7 +212,7 @@ func (c Connection) RemoveCloud(ctx context.Context, tag names.CloudTag) error {
// GrantCloudAccess gives the given user the given access level on the
// given cloud. GrantCloudAccess uses the ModifyCloudAccess procedure on
// the Cloud facade.
func (c Connection) GrantCloudAccess(ctx context.Context, cloudTag names.CloudTag, userTag names.UserTag, access string) error {
func (c *Connection) GrantCloudAccess(ctx context.Context, cloudTag names.CloudTag, userTag names.UserTag, access string) error {
const op = errors.Op("jujuclient.GrantCloudAccess")
args := jujuparams.ModifyCloudAccessRequest{
Changes: []jujuparams.ModifyCloudAccess{{
Expand All @@ -239,7 +239,7 @@ func (c Connection) GrantCloudAccess(ctx context.Context, cloudTag names.CloudTa
// RevokeCloudAccess revokes the given access level on the given cloud from
// the given user. RevokeCloudAccess uses the ModifyCloudAccess procedure
// on the Cloud facade.
func (c Connection) RevokeCloudAccess(ctx context.Context, cloudTag names.CloudTag, userTag names.UserTag, access string) error {
func (c *Connection) RevokeCloudAccess(ctx context.Context, cloudTag names.CloudTag, userTag names.UserTag, access string) error {
const op = errors.Op("jujuclient.RevokeCloudAccess")
args := jujuparams.ModifyCloudAccessRequest{
Changes: []jujuparams.ModifyCloudAccess{{
Expand All @@ -265,7 +265,7 @@ func (c Connection) RevokeCloudAccess(ctx context.Context, cloudTag names.CloudT

// CloudInfo retrieves information about the cloud with the given name.
// CloudInfo uses the CloudInfo procedure on the Cloud facade.
func (c Connection) CloudInfo(ctx context.Context, tag names.CloudTag, ci *jujuparams.CloudInfo) error {
func (c *Connection) CloudInfo(ctx context.Context, tag names.CloudTag, ci *jujuparams.CloudInfo) error {
const op = errors.Op("jujuclient.CloudInfo")
args := jujuparams.Entities{
Entities: []jujuparams.Entity{{Tag: tag.String()}},
Expand All @@ -288,7 +288,7 @@ func (c Connection) CloudInfo(ctx context.Context, tag names.CloudTag, ci *jujup

// UpdateCloud updates the given cloud with the given cloud definition.
// UpdateCloud uses the UpdateCloud procedure on the cloud facade.
func (c Connection) UpdateCloud(ctx context.Context, tag names.CloudTag, cloud jujuparams.Cloud) error {
func (c *Connection) UpdateCloud(ctx context.Context, tag names.CloudTag, cloud jujuparams.Cloud) error {
const op = errors.Op("jujuclient.UpdateCloud")

args := jujuparams.UpdateCloudArgs{
Expand Down
39 changes: 32 additions & 7 deletions internal/jujuclient/dial.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"github.com/go-macaroon-bakery/macaroon-bakery/v3/httpbakery"
jujuhttp "github.com/juju/http/v2"
"github.com/juju/juju/api/base"
"github.com/juju/juju/core/permission"
jujuparams "github.com/juju/juju/rpc/params"
"github.com/juju/names/v5"
"github.com/juju/zaputil/zapctx"
Expand Down Expand Up @@ -54,15 +55,13 @@ type Dialer struct {
JWTService *jimmjwx.JWTService
}

// createLoginRequest formats a login request for Juju utilising a JWT.
func (d *Dialer) createLoginRequest(ctx context.Context, ctl *dbmodel.Controller, modelTag names.ModelTag, p map[string]string) (*jujuparams.LoginRequest, error) {
// JIMM is automatically given all required permissions
permissions := p
if permissions == nil {
permissions = make(map[string]string)
}
permissions[ctl.ResourceTag().String()] = "superuser"
if modelTag.Id() != "" {
permissions[modelTag.String()] = "admin"

permissions, err := d.maybeCorrectPermissionMap(p, ctl)
if err != nil {
return nil, err
}

jwt, err := d.JWTService.NewJWT(ctx, jimmjwx.JWTParams{
Expand All @@ -82,6 +81,30 @@ func (d *Dialer) createLoginRequest(ctx context.Context, ctl *dbmodel.Controller
}, nil
}

func (d *Dialer) maybeCorrectPermissionMap(permissions map[string]string, ctl *dbmodel.Controller) (map[string]string, error) {
if permissions == nil {
permissions = make(map[string]string)
}

// Check the access level for the controller.
access, ok := permissions[ctl.ResourceTag().String()]

// If a permission cannot be found set a required default.
if !ok {
// Minimum required permission to connect to a controller
// is login.
permissions[ctl.ResourceTag().String()] = string(permission.LoginAccess)
} else {
// If the permission was set ahead of time, we ensure it's a valid controller
// permission.
if err := permission.ValidateControllerAccess(permission.Access(access)); err != nil {
return nil, errors.E(err)
}
}

return permissions, nil
}

// Dial implements jimm.Dialer.
func (d *Dialer) Dial(ctx context.Context, ctl *dbmodel.Controller, modelTag names.ModelTag, requiredPermissions map[string]string) (jimm.API, error) {
const op = errors.Op("jujuclient.Dial")
Expand Down Expand Up @@ -126,6 +149,7 @@ func (d *Dialer) Dial(ctx context.Context, ctl *dbmodel.Controller, modelTag nam

monitorC := make(chan struct{})
broken := new(uint32)

go pinger(client, ct.Id(), monitorC, broken)
return &Connection{
ctx: ctx,
Expand Down Expand Up @@ -237,6 +261,7 @@ func (c *Connection) redial(ctx context.Context, requiredPermissions map[string]
if err = c.Close(); err != nil {
return errors.E(op, err)
}

conn := api.(*Connection)
c.client = conn.client
c.userTag = conn.userTag
Expand Down
Loading
Loading