mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2026-01-26 15:02:52 -05:00
Merge pull request #62 from owncloud/revert-61-revert-60-roles-manager
Bring back "Roles manager" after release
This commit is contained in:
6
changelog/unreleased/roles-manager.md
Normal file
6
changelog/unreleased/roles-manager.md
Normal file
@@ -0,0 +1,6 @@
|
||||
Change: Roles manager
|
||||
|
||||
We combined the roles middleware and cache into a roles manager. The manager doesn't expose the cache anymore and manages
|
||||
the state of the cache by fetching roles from the role service which don't exist in the cache, yet.
|
||||
|
||||
https://github.com/owncloud/ocis-pkg/pull/60
|
||||
@@ -1,66 +0,0 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
"github.com/owncloud/ocis-pkg/v2/roles"
|
||||
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
|
||||
)
|
||||
|
||||
// Roles manages a roles.Cache by fetching and inserting roles unknown by the cache.
|
||||
// Relevant roleIDs are extracted from the metadata context, i.e. the roleIDs of the authenticated user.
|
||||
func Roles(log log.Logger, rs settings.RoleService, cache *roles.Cache) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
// get roleIDs from context
|
||||
roleIDs, ok := ReadRoleIDsFromContext(r.Context())
|
||||
if !ok {
|
||||
log.Debug().Msg("failed to read roleIDs from context")
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
|
||||
// check which roles are not cached, yet
|
||||
lookup := make([]string, 0)
|
||||
for _, roleID := range roleIDs {
|
||||
if hit := cache.Get(roleID); hit == nil {
|
||||
lookup = append(lookup, roleID)
|
||||
}
|
||||
}
|
||||
|
||||
// fetch roles
|
||||
if len(lookup) > 0 {
|
||||
request := &settings.ListBundlesRequest{
|
||||
BundleIds: lookup,
|
||||
}
|
||||
res, err := rs.ListRoles(r.Context(), request)
|
||||
if err != nil {
|
||||
log.Debug().Err(err).Msg("failed to fetch roles by roleIDs")
|
||||
next.ServeHTTP(w, r)
|
||||
return
|
||||
}
|
||||
for _, role := range res.Bundles {
|
||||
cache.Set(role.Id, role)
|
||||
}
|
||||
}
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// ReadRoleIDsFromContext extracts roleIDs from the metadata context and returns them as []string
|
||||
func ReadRoleIDsFromContext(ctx context.Context) (roleIDs []string, ok bool) {
|
||||
roleIDsJSON, ok := metadata.Get(ctx, RoleIDs)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
err := json.Unmarshal([]byte(roleIDsJSON), &roleIDs)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return roleIDs, true
|
||||
}
|
||||
@@ -13,27 +13,25 @@ type entry struct {
|
||||
inserted time.Time
|
||||
}
|
||||
|
||||
// Cache is a cache implementation for roles, keyed by roleIDs.
|
||||
type Cache struct {
|
||||
// cache is a cache implementation for roles, keyed by roleIDs.
|
||||
type cache struct {
|
||||
entries map[string]entry
|
||||
size int
|
||||
ttl time.Duration
|
||||
m sync.Mutex
|
||||
}
|
||||
|
||||
// NewCache returns a new instance of Cache.
|
||||
func NewCache(o ...Option) Cache {
|
||||
opts := newOptions(o...)
|
||||
|
||||
return Cache{
|
||||
size: opts.size,
|
||||
ttl: opts.ttl,
|
||||
// newCache returns a new instance of Cache.
|
||||
func newCache(size int, ttl time.Duration) cache {
|
||||
return cache{
|
||||
size: size,
|
||||
ttl: ttl,
|
||||
entries: map[string]entry{},
|
||||
}
|
||||
}
|
||||
|
||||
// Get gets a role-bundle by a given `roleID`.
|
||||
func (c *Cache) Get(roleID string) *settings.Bundle {
|
||||
// get gets a role-bundle by a given `roleID`.
|
||||
func (c *cache) get(roleID string) *settings.Bundle {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
@@ -43,23 +41,8 @@ func (c *Cache) Get(roleID string) *settings.Bundle {
|
||||
return nil
|
||||
}
|
||||
|
||||
// FindPermissionByID searches for a permission-setting by the permissionID, but limited to the given roleIDs
|
||||
func (c *Cache) FindPermissionByID(roleIDs []string, permissionID string) *settings.Setting {
|
||||
for _, roleID := range roleIDs {
|
||||
role := c.Get(roleID)
|
||||
if role != nil {
|
||||
for _, setting := range role.Settings {
|
||||
if setting.Id == permissionID {
|
||||
return setting
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Set sets a roleID / role-bundle.
|
||||
func (c *Cache) Set(roleID string, value *settings.Bundle) {
|
||||
// set sets a roleID / role-bundle.
|
||||
func (c *cache) set(roleID string, value *settings.Bundle) {
|
||||
c.m.Lock()
|
||||
defer c.m.Unlock()
|
||||
|
||||
@@ -73,8 +56,8 @@ func (c *Cache) Set(roleID string, value *settings.Bundle) {
|
||||
}
|
||||
}
|
||||
|
||||
// Evict frees memory from the cache by removing entries that exceeded the cache TTL.
|
||||
func (c *Cache) evict() {
|
||||
// evict frees memory from the cache by removing entries that exceeded the cache TTL.
|
||||
func (c *cache) evict() {
|
||||
for i := range c.entries {
|
||||
if c.entries[i].inserted.Add(c.ttl).Before(time.Now()) {
|
||||
delete(c.entries, i)
|
||||
@@ -82,12 +65,7 @@ func (c *Cache) evict() {
|
||||
}
|
||||
}
|
||||
|
||||
// Length returns the amount of entries.
|
||||
func (c *Cache) Length() int {
|
||||
return len(c.entries)
|
||||
}
|
||||
|
||||
// fits returns whether the cache is at full capacity.
|
||||
func (c *Cache) fits() bool {
|
||||
// fits returns whether the cache fits more entries.
|
||||
func (c *cache) fits() bool {
|
||||
return c.size > len(c.entries)
|
||||
}
|
||||
|
||||
69
roles/manager.go
Normal file
69
roles/manager.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package roles
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
|
||||
)
|
||||
|
||||
// Manager manages a cache of roles by fetching unknown roles from the settings.RoleService.
|
||||
type Manager struct {
|
||||
logger log.Logger
|
||||
cache cache
|
||||
roleService settings.RoleService
|
||||
}
|
||||
|
||||
// NewManager returns a new instance of Manager.
|
||||
func NewManager(o ...Option) Manager {
|
||||
opts := newOptions(o...)
|
||||
|
||||
return Manager{
|
||||
cache: newCache(opts.size, opts.ttl),
|
||||
roleService: opts.roleService,
|
||||
}
|
||||
}
|
||||
|
||||
// List returns all roles that match the given roleIDs.
|
||||
func (m *Manager) List(ctx context.Context, roleIDs []string) []*settings.Bundle {
|
||||
// get from cache
|
||||
result := make([]*settings.Bundle, 0)
|
||||
lookup := make([]string, 0)
|
||||
for _, roleID := range roleIDs {
|
||||
if hit := m.cache.get(roleID); hit == nil {
|
||||
lookup = append(lookup, roleID)
|
||||
} else {
|
||||
result = append(result, hit)
|
||||
}
|
||||
}
|
||||
|
||||
// if there are roles missing, fetch them from the RoleService
|
||||
if len(lookup) > 0 {
|
||||
request := &settings.ListBundlesRequest{
|
||||
BundleIds: lookup,
|
||||
}
|
||||
res, err := m.roleService.ListRoles(ctx, request)
|
||||
if err != nil {
|
||||
m.logger.Debug().Err(err).Msg("failed to fetch roles by roleIDs")
|
||||
}
|
||||
for _, role := range res.Bundles {
|
||||
m.cache.set(role.Id, role)
|
||||
result = append(result, role)
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// FindPermissionByID searches for a permission-setting by the permissionID, but limited to the given roleIDs
|
||||
func (m *Manager) FindPermissionByID(ctx context.Context, roleIDs []string, permissionID string) *settings.Setting {
|
||||
for _, role := range m.List(ctx, roleIDs) {
|
||||
for _, setting := range role.Settings {
|
||||
if setting.Id == permissionID {
|
||||
return setting
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -2,31 +2,50 @@ package roles
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/owncloud/ocis-pkg/v2/log"
|
||||
settings "github.com/owncloud/ocis-settings/pkg/proto/v0"
|
||||
)
|
||||
|
||||
// Options are all the possible options.
|
||||
type Options struct {
|
||||
size int
|
||||
ttl time.Duration
|
||||
size int
|
||||
ttl time.Duration
|
||||
logger log.Logger
|
||||
roleService settings.RoleService
|
||||
}
|
||||
|
||||
// Option mutates option
|
||||
type Option func(*Options)
|
||||
|
||||
// Size configures the size of the cache in items.
|
||||
func Size(s int) Option {
|
||||
// CacheSize configures the size of the cache in items.
|
||||
func CacheSize(s int) Option {
|
||||
return func(o *Options) {
|
||||
o.size = s
|
||||
}
|
||||
}
|
||||
|
||||
// TTL rebuilds the cache after the configured duration.
|
||||
func TTL(ttl time.Duration) Option {
|
||||
// CacheTTL rebuilds the cache after the configured duration.
|
||||
func CacheTTL(ttl time.Duration) Option {
|
||||
return func(o *Options) {
|
||||
o.ttl = ttl
|
||||
}
|
||||
}
|
||||
|
||||
// Logger sets a preconfigured logger
|
||||
func Logger(logger log.Logger) Option {
|
||||
return func(o *Options) {
|
||||
o.logger = logger
|
||||
}
|
||||
}
|
||||
|
||||
// RoleService provides endpoints for fetching roles.
|
||||
func RoleService(rs settings.RoleService) Option {
|
||||
return func(o *Options) {
|
||||
o.roleService = rs
|
||||
}
|
||||
}
|
||||
|
||||
func newOptions(opts ...Option) Options {
|
||||
o := Options{}
|
||||
|
||||
|
||||
22
roles/util.go
Normal file
22
roles/util.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package roles
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/micro/go-micro/v2/metadata"
|
||||
"github.com/owncloud/ocis-pkg/v2/middleware"
|
||||
)
|
||||
|
||||
// ReadRoleIDsFromContext extracts roleIDs from the metadata context and returns them as []string
|
||||
func ReadRoleIDsFromContext(ctx context.Context) (roleIDs []string, ok bool) {
|
||||
roleIDsJSON, ok := metadata.Get(ctx, middleware.RoleIDs)
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
err := json.Unmarshal([]byte(roleIDsJSON), &roleIDs)
|
||||
if err != nil {
|
||||
return nil, false
|
||||
}
|
||||
return roleIDs, true
|
||||
}
|
||||
Reference in New Issue
Block a user