wisski-cloud-distillery/internal/dis/component/auth/scope.go
2023-11-02 12:05:13 +01:00

74 lines
1.9 KiB
Go

package auth
import (
"errors"
"net/http"
"github.com/FAU-CDI/wisski-distillery/internal/dis/component"
)
var (
ErrUnknownScope = errors.New("unknown scope")
ErrParamRequired = errors.New("scope requires parameter")
ErrNoParam = errors.New("scope does not take parameter")
)
// Scopes returns a map of all available scopes
func (auth *Auth) Scopes() map[component.Scope]component.ScopeInfo {
scopes := auth.getScopeMap()
mp := make(map[component.Scope]component.ScopeInfo, len(scopes))
for scope, entry := range scopes {
mp[scope] = entry.Info
}
return mp
}
// getScopeMap return a (cached version of) all scopes
func (auth *Auth) getScopeMap() map[component.Scope]scopeMapEntry {
return auth.scopeMap.Get(func() map[component.Scope]scopeMapEntry {
mp := make(map[component.Scope]scopeMapEntry, len(auth.dependencies.ScopeProviders))
for _, p := range auth.dependencies.ScopeProviders {
info := p.Scope()
mp[info.Scope] = scopeMapEntry{
Provider: p,
Info: info,
}
}
return mp
})
}
// CheckScope checks if the given request is associated with the given request.
// A request can be one of two types:
// - A signed in user with an implicitly associated set of scopes
// - A session authorized with a token only
// If the request is denied a scope, the error will be of type AccessDeniedError.
func (auth *Auth) CheckScope(param string, scope component.Scope, r *http.Request) error {
// the empty scope is always permitted implicitly
if scope == "" {
return nil
}
entry, ok := auth.getScopeMap()[scope]
if !ok {
return ErrUnknownScope
}
// check that we take a parameter
if entry.Info.TakesParam && param == "" {
return ErrParamRequired
}
if !entry.Info.TakesParam && param != "" {
return ErrNoParam
}
// call the checker and return an error
ok, err := entry.Provider.HasScope(param, r)
if err != nil {
return entry.Info.CheckError(err)
}
if ok {
return nil
}
return entry.Info.DeniedError()
}