// changeModelAccess performs the requested access grant or revoke action for the // specified user on the specified model. func changeModelAccess(accessor common.ModelManagerBackend, modelTag names.ModelTag, apiUser, targetUserTag names.UserTag, action params.ModelAction, access permission.Access, userIsAdmin bool) error { st, err := accessor.ForModel(modelTag) if err != nil { return errors.Annotate(err, "could not lookup model") } defer st.Close() if err := userAuthorizedToChangeAccess(st, userIsAdmin, apiUser); err != nil { return errors.Trace(err) } switch action { case params.GrantModelAccess: _, err = st.AddModelUser(modelTag.Id(), state.UserAccessSpec{User: targetUserTag, CreatedBy: apiUser, Access: access}) if errors.IsAlreadyExists(err) { modelUser, err := st.UserAccess(targetUserTag, modelTag) if errors.IsNotFound(err) { // Conflicts with prior check, must be inconsistent state. err = txn.ErrExcessiveContention } if err != nil { return errors.Annotate(err, "could not look up model access for user") } // Only set access if greater access is being granted. if modelUser.Access.EqualOrGreaterModelAccessThan(access) { return errors.Errorf("user already has %q access or greater", access) } if _, err = st.SetUserAccess(modelUser.UserTag, modelUser.Object, access); err != nil { return errors.Annotate(err, "could not set model access for user") } return nil } return errors.Annotate(err, "could not grant model access") case params.RevokeModelAccess: switch access { case permission.ReadAccess: // Revoking read access removes all access. err := st.RemoveUserAccess(targetUserTag, modelTag) return errors.Annotate(err, "could not revoke model access") case permission.WriteAccess: // Revoking write access sets read-only. modelUser, err := st.UserAccess(targetUserTag, modelTag) if err != nil { return errors.Annotate(err, "could not look up model access for user") } _, err = st.SetUserAccess(modelUser.UserTag, modelUser.Object, permission.ReadAccess) return errors.Annotate(err, "could not set model access to read-only") case permission.AdminAccess: // Revoking admin access sets read-write. modelUser, err := st.UserAccess(targetUserTag, modelTag) if err != nil { return errors.Annotate(err, "could not look up model access for user") } _, err = st.SetUserAccess(modelUser.UserTag, modelUser.Object, permission.WriteAccess) return errors.Annotate(err, "could not set model access to read-write") default: return errors.Errorf("don't know how to revoke %q access", access) } default: return errors.Errorf("unknown action %q", action) } }