mirror of
https://github.com/SecurityBrewery/catalyst.git
synced 2025-12-06 15:22:47 +01:00
15
.github/workflows/ci.yml
vendored
15
.github/workflows/ci.yml
vendored
@@ -78,21 +78,6 @@ jobs:
|
||||
- run: go tool cover -func=cover.out
|
||||
- uses: codecov/codecov-action@v3
|
||||
|
||||
gocap:
|
||||
name: gocap
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/setup-go@v3
|
||||
with: { go-version: '1.18' }
|
||||
- uses: actions/checkout@v3
|
||||
- run: go mod download
|
||||
- run: go install github.com/cugu/gocap@main
|
||||
- run: |
|
||||
mkdir -p ui/dist/img
|
||||
touch ui/dist/index.html ui/dist/favicon.ico ui/dist/manifest.json ui/dist/img/fake.png
|
||||
- run: go list --json ./cmd/catalyst
|
||||
- run: gocap check ./cmd/catalyst
|
||||
|
||||
cypress:
|
||||
strategy:
|
||||
matrix:
|
||||
|
||||
@@ -3,6 +3,7 @@ run:
|
||||
timeout: 5m
|
||||
skip-dirs:
|
||||
- generated
|
||||
- internal
|
||||
linters:
|
||||
enable:
|
||||
- asciicheck
|
||||
|
||||
98
auth.go
Normal file
98
auth.go
Normal file
@@ -0,0 +1,98 @@
|
||||
package catalyst
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"errors"
|
||||
"fmt"
|
||||
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
)
|
||||
|
||||
type catalystResolver struct {
|
||||
database *database.Database
|
||||
}
|
||||
|
||||
func newCatalystResolver(db *database.Database) *catalystResolver {
|
||||
return &catalystResolver{
|
||||
database: db,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *catalystResolver) UserCreateIfNotExists(ctx context.Context, user *maut.User, password string) (err error) {
|
||||
if user != nil {
|
||||
if _, err := c.database.UserGet(ctx, user.ID); err == nil {
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
if user == nil || user.APIKey {
|
||||
_, err = c.database.UserCreateSetupAPIKey(ctx, password)
|
||||
} else {
|
||||
_, err = c.database.UserCreate(ctx, &model.UserForm{
|
||||
Apikey: user.APIKey,
|
||||
Blocked: user.Blocked,
|
||||
ID: user.ID,
|
||||
Password: &password,
|
||||
Roles: user.Roles,
|
||||
})
|
||||
}
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
func (c *catalystResolver) User(ctx context.Context, userID string) (*maut.User, error) {
|
||||
user, err := c.database.UserGet(ctx, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapMautUser(user), nil
|
||||
}
|
||||
|
||||
func (c *catalystResolver) UserAPIKeyByHash(ctx context.Context, key string) (*maut.User, error) {
|
||||
sha256Hash := fmt.Sprintf("%x", sha256.Sum256([]byte(key)))
|
||||
user, err := c.database.UserAPIKeyByHash(ctx, sha256Hash)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapMautUser(user), nil
|
||||
}
|
||||
|
||||
func (c *catalystResolver) UserByIDAndPassword(ctx context.Context, username string, password string) (*maut.User, error) {
|
||||
user, err := c.database.UserByIDAndPassword(ctx, username, password)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return mapMautUser(user), nil
|
||||
}
|
||||
|
||||
func (c *catalystResolver) Role(ctx context.Context, roleID string) (r *maut.Role, err error) {
|
||||
switch roleID {
|
||||
case "admin":
|
||||
return Admin, nil
|
||||
case "engineer":
|
||||
return engineer, nil
|
||||
case "analyst":
|
||||
return analyst, nil
|
||||
}
|
||||
|
||||
return nil, errors.New("role not found")
|
||||
}
|
||||
|
||||
func mapMautUser(user *model.UserResponse) *maut.User {
|
||||
return &maut.User{
|
||||
ID: user.ID,
|
||||
APIKey: user.Apikey,
|
||||
Blocked: user.Blocked,
|
||||
// Email: user.Email, // TODO
|
||||
// Groups: user.Groups, // TODO
|
||||
// Name: user.Name, // TODO
|
||||
Roles: user.Roles,
|
||||
}
|
||||
}
|
||||
475
auth/auth.go
475
auth/auth.go
@@ -1,475 +0,0 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/hooks"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
SimpleAuthEnable bool
|
||||
APIKeyAuthEnable bool
|
||||
OIDCAuthEnable bool
|
||||
|
||||
OIDCIssuer string
|
||||
AuthURL string
|
||||
OAuth2 *oauth2.Config
|
||||
UserCreateConfig *UserCreateConfig
|
||||
|
||||
provider *oidc.Provider
|
||||
}
|
||||
|
||||
type UserCreateConfig struct {
|
||||
AuthBlockNew bool
|
||||
AuthDefaultRoles []role.Role
|
||||
AuthAdminUsers []string
|
||||
|
||||
OIDCClaimUsername string
|
||||
OIDCClaimEmail string
|
||||
OIDCClaimName string
|
||||
// OIDCClaimGroups string
|
||||
}
|
||||
|
||||
func (c *Config) Verifier(ctx context.Context) (*oidc.IDTokenVerifier, error) {
|
||||
if c.provider == nil {
|
||||
if err := c.Load(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
config := &oidc.Config{ClientID: c.OAuth2.ClientID}
|
||||
if c.AuthURL != "" {
|
||||
config.SkipIssuerCheck = true
|
||||
}
|
||||
|
||||
return c.provider.Verifier(config), nil
|
||||
}
|
||||
|
||||
func (c *Config) Load(ctx context.Context) error {
|
||||
for {
|
||||
provider, err := oidc.NewProvider(ctx, c.OIDCIssuer)
|
||||
if err == nil {
|
||||
c.provider = provider
|
||||
c.OAuth2.Endpoint = provider.Endpoint()
|
||||
if c.AuthURL != "" {
|
||||
c.OAuth2.Endpoint.AuthURL = c.AuthURL
|
||||
}
|
||||
|
||||
break
|
||||
}
|
||||
|
||||
if errors.Is(err, context.DeadlineExceeded) {
|
||||
return errors.New("could not load provider")
|
||||
}
|
||||
|
||||
log.Printf("could not load oidc provider: %s, retrying in 10 seconds\n", err)
|
||||
time.Sleep(time.Second * 10)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func Authenticate(db *database.Database, config *Config, jar *Jar) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
keyHeader := r.Header.Get("PRIVATE-TOKEN")
|
||||
authHeader := r.Header.Get("Authorization")
|
||||
|
||||
switch {
|
||||
case keyHeader != "":
|
||||
if config.APIKeyAuthEnable {
|
||||
keyAuth(db, keyHeader)(next).ServeHTTP(w, r)
|
||||
} else {
|
||||
api.JSONErrorStatus(w, http.StatusUnauthorized, errors.New("API Key authentication not enabled"))
|
||||
}
|
||||
case authHeader != "":
|
||||
if config.OIDCAuthEnable {
|
||||
iss := config.OIDCIssuer
|
||||
bearerAuth(db, authHeader, iss, config, jar)(next).ServeHTTP(w, r)
|
||||
} else {
|
||||
api.JSONErrorStatus(w, http.StatusUnauthorized, errors.New("OIDC authentication not enabled"))
|
||||
}
|
||||
default:
|
||||
sessionAuth(db, config, jar)(next).ServeHTTP(w, r)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func bearerAuth(db *database.Database, authHeader string, iss string, config *Config, jar *Jar) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
if !strings.HasPrefix(authHeader, "Bearer ") {
|
||||
api.JSONErrorStatus(w, http.StatusUnauthorized, errors.New("no bearer token"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
claims, apiError := verifyClaims(r, config, authHeader[7:])
|
||||
if apiError != nil {
|
||||
api.JSONErrorStatus(w, apiError.Status, apiError.Internal)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// if claims.Iss != iss {
|
||||
// return &api.HTTPError{Status: http.StatusInternalServerError, Internal: "wrong issuer"})
|
||||
// return
|
||||
// }
|
||||
|
||||
jar.setClaimsCookie(w, claims)
|
||||
|
||||
r, err := setContextClaims(r, db, claims, config)
|
||||
if err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, fmt.Errorf("could not load user: %w", err))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func keyAuth(db *database.Database, keyHeader string) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
h := fmt.Sprintf("%x", sha256.Sum256([]byte(keyHeader)))
|
||||
|
||||
key, err := db.UserAPIKeyByHash(r.Context(), h)
|
||||
if err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, fmt.Errorf("could not verify private token: %w", err))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r = setContextUser(r, key, db.Hooks)
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func sessionAuth(db *database.Database, config *Config, jar *Jar) func(next http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
claims, noCookie, err := jar.claimsCookie(r)
|
||||
if err != nil {
|
||||
deleteClaimsCookie(w)
|
||||
|
||||
api.JSONError(w, err)
|
||||
|
||||
return
|
||||
}
|
||||
if noCookie {
|
||||
redirectToLogin(config, jar)(w, r)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
r, err = setContextClaims(r, db, claims, config)
|
||||
if err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, fmt.Errorf("could not load user: %w", err))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setContextClaims(r *http.Request, db *database.Database, claims map[string]any, config *Config) (*http.Request, error) {
|
||||
newUser, newSetting, err := mapUserAndSettings(claims, config.UserCreateConfig)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, ok := busdb.UserFromContext(r.Context()); !ok {
|
||||
r = busdb.SetContext(r, &model.UserResponse{ID: "auth", Roles: []string{role.Admin}, Apikey: false, Blocked: false})
|
||||
}
|
||||
|
||||
user, err := db.UserGetOrCreate(r.Context(), newUser)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if _, err = db.UserDataGetOrCreate(r.Context(), newUser.ID, newSetting); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return setContextUser(r, user, db.Hooks), nil
|
||||
}
|
||||
|
||||
func setContextUser(r *http.Request, user *model.UserResponse, hooks *hooks.Hooks) *http.Request {
|
||||
groups, err := hooks.GetGroups(r.Context(), user.ID)
|
||||
if err == nil {
|
||||
r = busdb.SetGroupContext(r, groups)
|
||||
}
|
||||
|
||||
return busdb.SetContext(r, user)
|
||||
}
|
||||
|
||||
func mapUserAndSettings(claims map[string]any, config *UserCreateConfig) (*model.UserForm, *model.UserData, error) {
|
||||
// handle Bearer tokens
|
||||
// if typ, ok := claims["typ"]; ok && typ == "Bearer" {
|
||||
// return &model.User{
|
||||
// Username: "bot",
|
||||
// Blocked: false,
|
||||
// Email: pointer.String("bot@example.org"),
|
||||
// Roles: []string{"user:read", "settings:read", "ticket", "backup:read", "backup:restore"},
|
||||
// Name: pointer.String("Bot"),
|
||||
// }, nil
|
||||
// }
|
||||
|
||||
username, err := getString(claims, config.OIDCClaimUsername)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
email, err := getString(claims, config.OIDCClaimEmail)
|
||||
if err != nil {
|
||||
email = ""
|
||||
}
|
||||
|
||||
name, err := getString(claims, config.OIDCClaimName)
|
||||
if err != nil {
|
||||
name = ""
|
||||
}
|
||||
|
||||
roles := role.Strings(config.AuthDefaultRoles)
|
||||
if slices.Contains(config.AuthAdminUsers, username) {
|
||||
roles = append(roles, role.Admin)
|
||||
}
|
||||
|
||||
return &model.UserForm{
|
||||
ID: username,
|
||||
Blocked: config.AuthBlockNew,
|
||||
Roles: roles,
|
||||
}, &model.UserData{
|
||||
Email: &email,
|
||||
Name: &name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getString(m map[string]any, key string) (string, error) {
|
||||
if v, ok := m[key]; ok {
|
||||
if s, ok := v.(string); ok {
|
||||
return s, nil
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("mapping of %s failed, wrong type (%T)", key, v)
|
||||
}
|
||||
|
||||
return "", fmt.Errorf("mapping of %s failed, missing value", key)
|
||||
}
|
||||
|
||||
func redirectToLogin(config *Config, jar *Jar) func(http.ResponseWriter, *http.Request) {
|
||||
if config.SimpleAuthEnable {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
if config.OIDCAuthEnable {
|
||||
return redirectToOIDCLogin(config, jar)
|
||||
}
|
||||
|
||||
return func(writer http.ResponseWriter, request *http.Request) {
|
||||
api.JSONErrorStatus(writer, http.StatusForbidden, errors.New("unauthenticated"))
|
||||
}
|
||||
}
|
||||
|
||||
func redirectToOIDCLogin(config *Config, jar *Jar) func(http.ResponseWriter, *http.Request) {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
state, err := state()
|
||||
if err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("generating state failed"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
jar.setStateCookie(w, state)
|
||||
|
||||
http.Redirect(w, r, config.OAuth2.AuthCodeURL(state), http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func AuthorizeBlockedUser() func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := busdb.UserFromContext(r.Context())
|
||||
if !ok {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("no user in context"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if user.Blocked {
|
||||
api.JSONErrorStatus(w, http.StatusForbidden, errors.New("user is blocked"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func AuthorizeRole(roles []string) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
user, ok := busdb.UserFromContext(r.Context())
|
||||
if !ok {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("no user in context"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if !role.UserHasRoles(user, role.FromStrings(roles)) {
|
||||
api.JSONErrorStatus(w, http.StatusForbidden, fmt.Errorf("missing role %s has %s", roles, user.Roles))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
next.ServeHTTP(w, r)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func login(db *database.Database, jar *Jar) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
type credentials struct {
|
||||
Username string
|
||||
Password string
|
||||
}
|
||||
cr := credentials{}
|
||||
|
||||
if err := json.NewDecoder(r.Body).Decode(&cr); err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusUnauthorized, errors.New("wrong username or password"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
user, err := db.UserByIDAndPassword(r.Context(), cr.Username, cr.Password)
|
||||
if err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusUnauthorized, errors.New("wrong username or password"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
userdata, err := db.UserDataGet(r.Context(), user.ID)
|
||||
if err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusUnauthorized, errors.New("no userdata"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
jar.setClaimsCookie(w, map[string]any{
|
||||
"preferred_username": user.ID,
|
||||
"name": userdata.Name,
|
||||
"email": userdata.Email,
|
||||
})
|
||||
|
||||
b, _ := json.Marshal(map[string]string{"login": "successful"})
|
||||
_, _ = w.Write(b)
|
||||
}
|
||||
}
|
||||
|
||||
func logout() http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
deleteClaimsCookie(w)
|
||||
|
||||
http.Redirect(w, r, "/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func callback(config *Config, jar *Jar) http.HandlerFunc {
|
||||
return func(w http.ResponseWriter, r *http.Request) {
|
||||
state, err := jar.stateCookie(r)
|
||||
if err != nil || state == "" {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("state missing"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
if state != r.URL.Query().Get("state") {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("state mismatch"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
oauth2Token, err := config.OAuth2.Exchange(r.Context(), r.URL.Query().Get("code"))
|
||||
if err != nil {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, fmt.Errorf("oauth2 exchange failed: %w", err))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// Extract the ID Token from OAuth2 token.
|
||||
rawIDToken, ok := oauth2Token.Extra("id_token").(string)
|
||||
if !ok {
|
||||
api.JSONErrorStatus(w, http.StatusInternalServerError, errors.New("missing id token"))
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
claims, apiError := verifyClaims(r, config, rawIDToken)
|
||||
if apiError != nil {
|
||||
api.JSONErrorStatus(w, apiError.Status, apiError.Internal)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
jar.setClaimsCookie(w, claims)
|
||||
|
||||
http.Redirect(w, r, "/ui/", http.StatusFound)
|
||||
}
|
||||
}
|
||||
|
||||
func state() (string, error) {
|
||||
rnd := make([]byte, 32)
|
||||
if _, err := rand.Read(rnd); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return base64.URLEncoding.EncodeToString(rnd), nil
|
||||
}
|
||||
|
||||
func verifyClaims(r *http.Request, config *Config, rawIDToken string) (map[string]any, *api.HTTPError) {
|
||||
verifier, err := config.Verifier(r.Context())
|
||||
if err != nil {
|
||||
return nil, &api.HTTPError{Status: http.StatusUnauthorized, Internal: fmt.Errorf("could not verify: %w", err)}
|
||||
}
|
||||
|
||||
authToken, err := verifier.Verify(r.Context(), rawIDToken)
|
||||
if err != nil {
|
||||
return nil, &api.HTTPError{Status: http.StatusInternalServerError, Internal: fmt.Errorf("could not verify bearer token: %w", err)}
|
||||
}
|
||||
|
||||
var claims map[string]any
|
||||
if err := authToken.Claims(&claims); err != nil {
|
||||
return nil, &api.HTTPError{Status: http.StatusInternalServerError, Internal: fmt.Errorf("failed to parse claims: %w", err)}
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
}
|
||||
@@ -1,84 +0,0 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"log"
|
||||
"net/http"
|
||||
|
||||
"github.com/gorilla/securecookie"
|
||||
"golang.org/x/crypto/argon2"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/generated/time"
|
||||
)
|
||||
|
||||
const (
|
||||
stateSessionCookie = "state"
|
||||
userSessionCookie = "user"
|
||||
)
|
||||
|
||||
type Jar struct {
|
||||
store *securecookie.SecureCookie
|
||||
}
|
||||
|
||||
func NewJar(secret []byte) *Jar {
|
||||
hashSalt := securecookie.GenerateRandomKey(64)
|
||||
blockSalt := securecookie.GenerateRandomKey(64)
|
||||
|
||||
return &Jar{
|
||||
store: securecookie.New(
|
||||
argon2.IDKey(secret, hashSalt, 1, 64*1024, 4, 64),
|
||||
argon2.IDKey(secret, blockSalt, 1, 64*1024, 4, 32),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
func (j *Jar) setStateCookie(w http.ResponseWriter, state string) {
|
||||
encoded, err := j.store.Encode(userSessionCookie, state)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
tomorrow := time.Now().AddDate(0, 0, 1)
|
||||
http.SetCookie(w, &http.Cookie{Name: stateSessionCookie, Value: encoded, Path: "/", Expires: tomorrow})
|
||||
}
|
||||
|
||||
func (j *Jar) stateCookie(r *http.Request) (string, error) {
|
||||
stateCookie, err := r.Cookie(stateSessionCookie)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
var state string
|
||||
err = j.store.Decode(userSessionCookie, stateCookie.Value, &state)
|
||||
|
||||
return state, err
|
||||
}
|
||||
|
||||
func (j *Jar) setClaimsCookie(w http.ResponseWriter, claims map[string]any) {
|
||||
encoded, err := j.store.Encode(userSessionCookie, claims)
|
||||
if err != nil {
|
||||
log.Println(err)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
tomorrow := time.Now().AddDate(0, 0, 1)
|
||||
http.SetCookie(w, &http.Cookie{Name: userSessionCookie, Value: encoded, Path: "/", Expires: tomorrow})
|
||||
}
|
||||
|
||||
func deleteClaimsCookie(w http.ResponseWriter) {
|
||||
http.SetCookie(w, &http.Cookie{Name: userSessionCookie, Value: "", MaxAge: -1})
|
||||
}
|
||||
|
||||
func (j *Jar) claimsCookie(r *http.Request) (map[string]any, bool, error) {
|
||||
userCookie, err := r.Cookie(userSessionCookie)
|
||||
if err != nil {
|
||||
return nil, true, nil
|
||||
}
|
||||
|
||||
var claims map[string]any
|
||||
err = j.store.Decode(userSessionCookie, userCookie.Value, &claims)
|
||||
|
||||
return claims, false, err
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
)
|
||||
|
||||
func Server(config *Config, catalystDatabase *database.Database, jar *Jar) *chi.Mux {
|
||||
server := chi.NewRouter()
|
||||
|
||||
server.Get("/config", hasOIDC(config))
|
||||
|
||||
if config.OIDCAuthEnable {
|
||||
server.Get("/callback", callback(config, jar))
|
||||
server.Get("/oidclogin", redirectToOIDCLogin(config, jar))
|
||||
}
|
||||
if config.SimpleAuthEnable {
|
||||
server.Post("/login", login(catalystDatabase, jar))
|
||||
}
|
||||
server.Post("/logout", logout())
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func hasOIDC(config *Config) func(writer http.ResponseWriter, request *http.Request) {
|
||||
return func(writer http.ResponseWriter, request *http.Request) {
|
||||
b, err := json.Marshal(map[string]any{
|
||||
"simple": config.SimpleAuthEnable,
|
||||
"oidc": config.OIDCAuthEnable,
|
||||
})
|
||||
if err != nil {
|
||||
writer.WriteHeader(http.StatusInternalServerError)
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
_, _ = writer.Write(b)
|
||||
}
|
||||
}
|
||||
@@ -4,12 +4,12 @@ import (
|
||||
"context"
|
||||
"log"
|
||||
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/generated/time"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
)
|
||||
|
||||
type busService struct {
|
||||
@@ -30,9 +30,9 @@ func New(apiURL, apikey, network string, catalystBus *bus.Bus, db *database.Data
|
||||
|
||||
func busContext() context.Context {
|
||||
// TODO: change roles?
|
||||
bot := &model.UserResponse{ID: "bot", Roles: []string{role.Admin}}
|
||||
bot := &maut.User{ID: "bot", Roles: []string{maut.AdminRole}}
|
||||
|
||||
return busdb.UserContext(context.Background(), bot)
|
||||
return maut.UserContext(context.Background(), bot, nil) // TODO add permissions ?
|
||||
}
|
||||
|
||||
func (h *busService) logRequest(msg *bus.RequestMsg) {
|
||||
|
||||
@@ -8,15 +8,14 @@ import (
|
||||
"time"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst"
|
||||
"github.com/SecurityBrewery/catalyst/cmd"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/generated/pointer"
|
||||
"github.com/SecurityBrewery/catalyst/hooks"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
"github.com/SecurityBrewery/catalyst/test"
|
||||
)
|
||||
|
||||
@@ -36,8 +35,8 @@ func main() {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
demoUser := &model.UserResponse{ID: "demo", Roles: []string{role.Admin}}
|
||||
ctx := busdb.UserContext(context.Background(), demoUser)
|
||||
demoUser := &maut.User{ID: "demo", Roles: []string{maut.AdminRole}}
|
||||
ctx := maut.UserContext(context.Background(), demoUser, catalyst.Admin.Permissions)
|
||||
if err := test.SetupTestData(ctx, theCatalyst.DB); err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
|
||||
23
cmd/cmd.go
23
cmd/cmd.go
@@ -6,13 +6,12 @@ import (
|
||||
"github.com/alecthomas/kong"
|
||||
kongyaml "github.com/alecthomas/kong-yaml"
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
"golang.org/x/exp/slices"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst"
|
||||
"github.com/SecurityBrewery/catalyst/auth"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
"github.com/SecurityBrewery/catalyst/storage"
|
||||
)
|
||||
|
||||
@@ -73,10 +72,6 @@ func ParseCatalystConfig() (*catalyst.Config, error) {
|
||||
}
|
||||
|
||||
func MapConfig(cli CLI) (*catalyst.Config, error) {
|
||||
roles := role.Explode(role.Analyst)
|
||||
roles = append(roles, role.Explodes(cli.AuthDefaultRoles)...)
|
||||
roles = role.Explodes(role.Strings(roles))
|
||||
|
||||
scopes := slices.Compact(append([]string{oidc.ScopeOpenID, "profile", "email"}, cli.OIDCScopes...))
|
||||
config := &catalyst.Config{
|
||||
IndexPath: cli.IndexPath,
|
||||
@@ -87,32 +82,34 @@ func MapConfig(cli CLI) (*catalyst.Config, error) {
|
||||
Password: cli.ArangoDBPassword,
|
||||
},
|
||||
Storage: &storage.Config{Host: cli.S3Host, User: cli.S3User, Password: cli.S3Password},
|
||||
Secret: []byte(cli.Secret),
|
||||
ExternalAddress: cli.ExternalAddress,
|
||||
InternalAddress: cli.CatalystAddress,
|
||||
Port: cli.Port,
|
||||
Auth: &auth.Config{
|
||||
Auth: &maut.Config{
|
||||
CookieSecret: []byte(cli.Secret),
|
||||
SimpleAuthEnable: false, // cli.SimpleAuthEnable,
|
||||
APIKeyAuthEnable: cli.APIKeyAuthEnable,
|
||||
OIDCAuthEnable: cli.OIDCEnable,
|
||||
OIDCIssuer: cli.OIDCIssuer,
|
||||
AuthURL: cli.AuthURL,
|
||||
// InitialUser: "",
|
||||
// InitialPassword: "",
|
||||
InitialAPIKey: cli.InitialAPIKey,
|
||||
OIDCIssuer: cli.OIDCIssuer,
|
||||
AuthURL: cli.AuthURL,
|
||||
OAuth2: &oauth2.Config{
|
||||
ClientID: cli.OIDCClientID,
|
||||
ClientSecret: cli.OIDCClientSecret,
|
||||
RedirectURL: cli.ExternalAddress + "/auth/callback",
|
||||
Scopes: scopes,
|
||||
},
|
||||
UserCreateConfig: &auth.UserCreateConfig{
|
||||
UserCreateConfig: &maut.UserCreateConfig{
|
||||
AuthBlockNew: cli.AuthBlockNew,
|
||||
AuthDefaultRoles: roles,
|
||||
AuthDefaultRoles: cli.AuthDefaultRoles,
|
||||
AuthAdminUsers: cli.AuthAdminUsers,
|
||||
OIDCClaimUsername: cli.OIDCClaimUsername,
|
||||
OIDCClaimEmail: cli.OIDCClaimEmail,
|
||||
OIDCClaimName: cli.OIDCClaimName,
|
||||
},
|
||||
},
|
||||
InitialAPIKey: cli.InitialAPIKey,
|
||||
}
|
||||
|
||||
return config, nil
|
||||
|
||||
@@ -1,38 +0,0 @@
|
||||
package busdb
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
)
|
||||
|
||||
type contextKey string
|
||||
|
||||
const (
|
||||
userContextKey contextKey = "user"
|
||||
groupContextKey contextKey = "groups"
|
||||
)
|
||||
|
||||
func SetContext(r *http.Request, user *model.UserResponse) *http.Request {
|
||||
user.Roles = role.Strings(role.Explodes(user.Roles))
|
||||
|
||||
return r.WithContext(context.WithValue(r.Context(), userContextKey, user))
|
||||
}
|
||||
|
||||
func SetGroupContext(r *http.Request, groups []string) *http.Request {
|
||||
return r.WithContext(context.WithValue(r.Context(), groupContextKey, groups))
|
||||
}
|
||||
|
||||
func UserContext(ctx context.Context, user *model.UserResponse) context.Context {
|
||||
user.Roles = role.Strings(role.Explodes(user.Roles))
|
||||
|
||||
return context.WithValue(ctx, userContextKey, user)
|
||||
}
|
||||
|
||||
func UserFromContext(ctx context.Context) (*model.UserResponse, bool) {
|
||||
u, ok := ctx.Value(userContextKey).(*model.UserResponse)
|
||||
|
||||
return u, ok
|
||||
}
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
"strings"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
@@ -15,7 +16,7 @@ import (
|
||||
const LogCollectionName = "logs"
|
||||
|
||||
func (db *BusDatabase) LogCreate(ctx context.Context, logType, reference, message string) (*model.LogEntry, error) {
|
||||
user, ok := UserFromContext(ctx)
|
||||
user, _, ok := maut.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no user in context")
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ func generateMigrations() ([]Migration, error) {
|
||||
&updateDocument[model.Settings]{ID: "update-settings-global-1", Collection: "settings", Key: "global", Document: &model.Settings{ArtifactStates: []*model.Type{{Icon: "mdi-help-circle-outline", ID: "unknown", Name: "Unknown", Color: pointer.String(model.TypeColorInfo)}, {Icon: "mdi-skull", ID: "malicious", Name: "Malicious", Color: pointer.String(model.TypeColorError)}, {Icon: "mdi-check", ID: "clean", Name: "Clean", Color: pointer.String(model.TypeColorSuccess)}}, ArtifactKinds: []*model.Type{{Icon: "mdi-server", ID: "asset", Name: "Asset"}, {Icon: "mdi-bullseye", ID: "ioc", Name: "IOC"}}, Timeformat: "yyyy-MM-dd hh:mm:ss"}},
|
||||
|
||||
&updateSchema{ID: "update-user-simple-login", Name: "users", DataType: "user", Schema: `{"type":"object","properties":{"apikey":{"type":"boolean"},"blocked":{"type":"boolean"},"roles":{"items":{"type":"string"},"type":"array"},"salt":{"type":"string"},"sha256":{"type":"string"},"sha512":{"type":"string"}},"required":["blocked","apikey","roles"],"$id":"#/definitions/User"}`},
|
||||
|
||||
&mapRoles{ID: "simplify-roles"},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -232,3 +234,17 @@ func (m *updateDocument[T]) Migrate(ctx context.Context, driver driver.Database)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
type mapRoles struct {
|
||||
ID string
|
||||
}
|
||||
|
||||
func (m mapRoles) MID() string {
|
||||
return m.ID
|
||||
}
|
||||
|
||||
func (m mapRoles) Migrate(ctx context.Context, driver driver.Database) error {
|
||||
_, err := driver.Query(ctx, "FOR u IN users UPDATE u WITH {roles: u.roles[*].name} IN users", nil)
|
||||
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/iancoleman/strcase"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
"github.com/mingrammer/commonregex"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
@@ -110,7 +111,7 @@ func (db *Database) AddComment(ctx context.Context, id int64, comment *model.Com
|
||||
}
|
||||
|
||||
if comment.Creator == nil || *comment.Creator == "" {
|
||||
user, exists := busdb.UserFromContext(ctx)
|
||||
user, _, exists := maut.UserFromContext(ctx)
|
||||
if !exists {
|
||||
return nil, errors.New("no user in context")
|
||||
}
|
||||
|
||||
@@ -11,12 +11,12 @@ import (
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/iancoleman/strcase"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/generated/pointer"
|
||||
"github.com/SecurityBrewery/catalyst/generated/time"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
)
|
||||
|
||||
var letters = []rune("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_")
|
||||
@@ -35,11 +35,9 @@ func generateKey() string {
|
||||
}
|
||||
|
||||
func toUser(user *model.UserForm, salt, sha256, sha512 *string) *model.User {
|
||||
roles := []string{}
|
||||
roles = append(roles, role.Strings(role.Explodes(user.Roles))...)
|
||||
u := &model.User{
|
||||
Blocked: user.Blocked,
|
||||
Roles: roles,
|
||||
Roles: user.Roles,
|
||||
Salt: salt,
|
||||
Sha256: sha256,
|
||||
Sha512: sha512,
|
||||
@@ -94,7 +92,7 @@ func (db *Database) UserCreate(ctx context.Context, newUser *model.UserForm) (*m
|
||||
var key, salt, sha256Hash, sha512Hash *string
|
||||
if newUser.Apikey {
|
||||
key, sha256Hash = generateAPIKey()
|
||||
} else {
|
||||
} else if newUser.Password != nil {
|
||||
salt, sha512Hash = hashUserPassword(newUser)
|
||||
}
|
||||
|
||||
@@ -111,7 +109,7 @@ func (db *Database) UserCreate(ctx context.Context, newUser *model.UserForm) (*m
|
||||
func (db *Database) UserCreateSetupAPIKey(ctx context.Context, key string) (*model.UserResponse, error) {
|
||||
newUser := &model.UserForm{
|
||||
ID: "setup",
|
||||
Roles: []string{role.Admin},
|
||||
Roles: []string{maut.AdminRole},
|
||||
Apikey: true,
|
||||
Blocked: false,
|
||||
}
|
||||
|
||||
@@ -28,16 +28,6 @@ paths:
|
||||
- { icon: "mdi-help-circle-outline", id: "unknown", name: "Unknown", color: "info" }
|
||||
- { icon: "mdi-skull", id: "malicious", name: "Malicious", color: "error" }
|
||||
- { icon: "mdi-check", id: "clean", name: "Clean", color: "success" }
|
||||
roles: [
|
||||
"admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write",
|
||||
"admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read",
|
||||
"admin:userdata:write", "analyst:automation:read",
|
||||
"analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read",
|
||||
"analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read",
|
||||
"analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write",
|
||||
"analyst:tickettype:read", "analyst:user:read", "engineer:automation:write",
|
||||
"engineer:playbook:write", "engineer:rule:write", "engineer:template:write",
|
||||
"engineer:tickettype:write" ]
|
||||
security: [ { roles: [ "settings:read" ] } ]
|
||||
post:
|
||||
tags: [ "settings" ]
|
||||
@@ -66,16 +56,6 @@ paths:
|
||||
- { icon: "mdi-help-circle-outline", id: "unknown", name: "Unknown", color: "info" }
|
||||
- { icon: "mdi-skull", id: "malicious", name: "Malicious", color: "error" }
|
||||
- { icon: "mdi-check", id: "clean", name: "Clean", color: "success" }
|
||||
roles: [
|
||||
"admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write",
|
||||
"admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read",
|
||||
"admin:userdata:write", "analyst:automation:read",
|
||||
"analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read",
|
||||
"analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read",
|
||||
"analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write",
|
||||
"analyst:tickettype:read", "analyst:user:read", "engineer:automation:write",
|
||||
"engineer:playbook:write", "engineer:rule:write", "engineer:template:write",
|
||||
"engineer:tickettype:write" ]
|
||||
security: [ { roles: [ "settings:write" ] } ]
|
||||
|
||||
definitions:
|
||||
|
||||
@@ -12,7 +12,7 @@ paths:
|
||||
description: "successful operation"
|
||||
schema: { $ref: "#/definitions/UserResponse" }
|
||||
examples:
|
||||
test: { id: bob, roles: [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read","analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ], blocked: false, apikey: false }
|
||||
test: { id: bob, roles: [ "admin" ], blocked: false, apikey: false }
|
||||
security: [ { roles: [ "currentuser:read" ] } ]
|
||||
|
||||
/users:
|
||||
@@ -26,8 +26,8 @@ paths:
|
||||
schema: { type: array, items: { $ref: "#/definitions/UserResponse" } }
|
||||
examples:
|
||||
test:
|
||||
- { id: bob, blocked: false, roles: [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ], apikey: false }
|
||||
- { id: script, roles: [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ], blocked: false, apikey: true }
|
||||
- { id: bob, blocked: false, roles: [ "admin" ], apikey: false }
|
||||
- { id: script, roles: [ "engineer" ], blocked: false, apikey: true }
|
||||
security: [ { roles: [ "user:read" ] } ]
|
||||
post:
|
||||
tags: [ "users" ]
|
||||
@@ -40,7 +40,7 @@ paths:
|
||||
description: "successful operation"
|
||||
schema: { $ref: "#/definitions/NewUserResponse" }
|
||||
examples:
|
||||
test: { id: "syncscript", roles: [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read" ], secret: "v39bOuobnlEljfWzjAgoKzhmnh1xSMxH", blocked: false }
|
||||
test: { id: "syncscript", roles: [ "analyst" ], secret: "v39bOuobnlEljfWzjAgoKzhmnh1xSMxH", blocked: false }
|
||||
security: [ { roles: [ "user:write" ] } ]
|
||||
/users/{id}:
|
||||
get:
|
||||
@@ -54,7 +54,7 @@ paths:
|
||||
description: "successful operation"
|
||||
schema: { $ref: "#/definitions/UserResponse" }
|
||||
examples:
|
||||
test: { id: "script", roles: [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ], blocked: false, apikey: true }
|
||||
test: { id: "script", roles: [ "engineer" ], blocked: false, apikey: true }
|
||||
security: [ { roles: [ "user:read" ] } ]
|
||||
put:
|
||||
tags: [ "users" ]
|
||||
@@ -70,7 +70,7 @@ paths:
|
||||
examples:
|
||||
test:
|
||||
id: bob
|
||||
roles: [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
roles: [ "analyst", "admin" ]
|
||||
apikey: false
|
||||
blocked: false
|
||||
security: [ { roles: [ "user:write" ] } ]
|
||||
|
||||
4
file.go
4
file.go
@@ -14,12 +14,12 @@ import (
|
||||
"github.com/aws/aws-sdk-go/service/s3"
|
||||
"github.com/aws/aws-sdk-go/service/s3/s3manager"
|
||||
"github.com/go-chi/chi/v5"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
tusd "github.com/tus/tusd/pkg/handler"
|
||||
"github.com/tus/tusd/pkg/s3store"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/storage"
|
||||
@@ -57,7 +57,7 @@ func tusdUpload(db *database.Database, catalystBus *bus.Bus, client *s3.S3, exte
|
||||
}
|
||||
|
||||
userID := "unknown"
|
||||
user, ok := busdb.UserFromContext(r.Context())
|
||||
user, _, ok := maut.UserFromContext(r.Context())
|
||||
if ok {
|
||||
userID = user.ID
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ mv generated/openapi.json generated/catalyst.json
|
||||
echo generate server and tests
|
||||
swagger-go-chi generated/community.yml generated
|
||||
rm -rf generated/auth generated/cli
|
||||
find generated -type f -name "*.go" -print0 | xargs -0 sed -i '' -e 's#"github.com/go-chi/chi"#"github.com/go-chi/chi/v5"#g'
|
||||
|
||||
echo generate typescript client
|
||||
openapi-generator generate -i generated/catalyst.yml -o ui/src/client -g typescript-axios --artifact-version 1.0.0-SNAPSHOT
|
||||
@@ -34,3 +35,6 @@ rm -rf ui/src/client/.openapi-generator ui/src/client/git_push.sh ui/src/client/
|
||||
|
||||
go mod tidy
|
||||
gci write --Section Standard --Section Default --Section "Prefix(github.com/SecurityBrewery/catalyst)" .
|
||||
cd internal/maut
|
||||
gci write --Section Standard --Section Default --Section "Prefix(github.com/jonas-plum/maut)" .
|
||||
cd ../..
|
||||
|
||||
@@ -7,7 +7,6 @@ import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/xeipuuv/gojsonschema"
|
||||
@@ -59,12 +58,30 @@ func parseQueryBool(r *http.Request, s string) (bool, error) {
|
||||
}
|
||||
|
||||
func parseQueryStringArray(r *http.Request, key string) ([]string, error) {
|
||||
return parseQueryArray(r, key), nil
|
||||
stringArray, ok := r.URL.Query()[key]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
return removeEmpty(stringArray), nil
|
||||
}
|
||||
|
||||
func removeEmpty(l []string) []string {
|
||||
var stringArray []string
|
||||
for _, s := range l {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
stringArray = append(stringArray, s)
|
||||
}
|
||||
|
||||
return stringArray
|
||||
}
|
||||
|
||||
func parseQueryBoolArray(r *http.Request, key string) ([]bool, error) {
|
||||
stringArray := parseQueryArray(r, key)
|
||||
|
||||
stringArray, ok := r.URL.Query()[key]
|
||||
if !ok {
|
||||
return nil, nil
|
||||
}
|
||||
var boolArray []bool
|
||||
for _, s := range stringArray {
|
||||
if s == "" {
|
||||
@@ -80,33 +97,6 @@ func parseQueryBoolArray(r *http.Request, key string) ([]bool, error) {
|
||||
return boolArray, nil
|
||||
}
|
||||
|
||||
func parseQueryArray(r *http.Request, key string) []string {
|
||||
stringArray, ok := r.URL.Query()[key]
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(stringArray) == 0 {
|
||||
return nil
|
||||
}
|
||||
|
||||
stringArray = strings.Split(stringArray[0], ",")
|
||||
|
||||
return removeEmpty(stringArray)
|
||||
}
|
||||
|
||||
func removeEmpty(l []string) []string {
|
||||
var stringArray []string
|
||||
for _, s := range l {
|
||||
if s == "" {
|
||||
continue
|
||||
}
|
||||
stringArray = append(stringArray, s)
|
||||
}
|
||||
|
||||
return stringArray
|
||||
}
|
||||
|
||||
func parseQueryOptionalInt(r *http.Request, key string) (*int, error) {
|
||||
s := r.URL.Query().Get(key)
|
||||
if s == "" {
|
||||
|
||||
@@ -1,86 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"reflect"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func Test_parseQueryOptionalBoolArray(t *testing.T) {
|
||||
type args struct {
|
||||
r *http.Request
|
||||
key string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []bool
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "bool array",
|
||||
args: args{
|
||||
r: httptest.NewRequest(
|
||||
http.MethodGet,
|
||||
"https://try.catalyst-soar.com/api/tickets?type=alert&offset=0&count=10&sort=status%2Cowner%2Ccreated&desc=true%2Cfalse%2Cfalse&query=status+%3D%3D+%27open%27+AND+%28owner+%3D%3D+%27eve%27+OR+%21owner%29",
|
||||
nil,
|
||||
),
|
||||
key: "desc",
|
||||
},
|
||||
want: []bool{true, false, false},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseQueryOptionalBoolArray(tt.args.r, tt.args.key)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseQueryOptionalBoolArray() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("parseQueryOptionalBoolArray() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_parseQueryOptionalStringArray(t *testing.T) {
|
||||
type args struct {
|
||||
r *http.Request
|
||||
key string
|
||||
}
|
||||
tests := []struct {
|
||||
name string
|
||||
args args
|
||||
want []string
|
||||
wantErr bool
|
||||
}{
|
||||
{
|
||||
name: "string array",
|
||||
args: args{
|
||||
r: httptest.NewRequest(
|
||||
http.MethodGet,
|
||||
"https://try.catalyst-soar.com/api/tickets?type=alert&offset=0&count=10&sort=status%2Cowner%2Ccreated&desc=true%2Cfalse%2Cfalse&query=status+%3D%3D+%27open%27+AND+%28owner+%3D%3D+%27eve%27+OR+%21owner%29",
|
||||
nil,
|
||||
),
|
||||
key: "sort",
|
||||
},
|
||||
want: []string{"status", "owner", "created"},
|
||||
wantErr: false,
|
||||
},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
got, err := parseQueryOptionalStringArray(tt.args.r, tt.args.key)
|
||||
if (err != nil) != tt.wantErr {
|
||||
t.Errorf("parseQueryOptionalStringArray() error = %v, wantErr %v", err, tt.wantErr)
|
||||
return
|
||||
}
|
||||
if !reflect.DeepEqual(got, tt.want) {
|
||||
t.Errorf("parseQueryOptionalStringArray() got = %v, want %v", got, tt.want)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -68,7 +68,7 @@ var Tests = []struct {
|
||||
Args: Args{Method: "Get", URL: "/currentuser"},
|
||||
Want: Want{
|
||||
Status: 200,
|
||||
Body: map[string]interface{}{"apikey": false, "blocked": false, "id": "bob", "roles": []interface{}{"admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write"}},
|
||||
Body: map[string]interface{}{"apikey": false, "blocked": false, "id": "bob", "roles": []interface{}{"admin"}},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -239,7 +239,7 @@ var Tests = []struct {
|
||||
Args: Args{Method: "Get", URL: "/settings"},
|
||||
Want: Want{
|
||||
Status: 200,
|
||||
Body: map[string]interface{}{"artifactKinds": []interface{}{map[string]interface{}{"icon": "mdi-server", "id": "asset", "name": "Asset"}, map[string]interface{}{"icon": "mdi-bullseye", "id": "ioc", "name": "IOC"}}, "artifactStates": []interface{}{map[string]interface{}{"color": "info", "icon": "mdi-help-circle-outline", "id": "unknown", "name": "Unknown"}, map[string]interface{}{"color": "error", "icon": "mdi-skull", "id": "malicious", "name": "Malicious"}, map[string]interface{}{"color": "success", "icon": "mdi-check", "id": "clean", "name": "Clean"}}, "roles": []interface{}{"admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write"}, "ticketTypes": []interface{}{map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-alert", "id": "alert", "name": "Alerts"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-radioactive", "id": "incident", "name": "Incidents"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-fingerprint", "id": "investigation", "name": "Forensic Investigations"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-target", "id": "hunt", "name": "Threat Hunting"}}, "tier": "community", "timeformat": "yyyy-MM-dd hh:mm:ss", "version": "0.0.0-test"},
|
||||
Body: map[string]interface{}{"artifactKinds": []interface{}{map[string]interface{}{"icon": "mdi-server", "id": "asset", "name": "Asset"}, map[string]interface{}{"icon": "mdi-bullseye", "id": "ioc", "name": "IOC"}}, "artifactStates": []interface{}{map[string]interface{}{"color": "info", "icon": "mdi-help-circle-outline", "id": "unknown", "name": "Unknown"}, map[string]interface{}{"color": "error", "icon": "mdi-skull", "id": "malicious", "name": "Malicious"}, map[string]interface{}{"color": "success", "icon": "mdi-check", "id": "clean", "name": "Clean"}}, "ticketTypes": []interface{}{map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-alert", "id": "alert", "name": "Alerts"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-radioactive", "id": "incident", "name": "Incidents"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-fingerprint", "id": "investigation", "name": "Forensic Investigations"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-target", "id": "hunt", "name": "Threat Hunting"}}, "tier": "community", "timeformat": "yyyy-MM-dd hh:mm:ss", "version": "0.0.0-test"},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -248,7 +248,7 @@ var Tests = []struct {
|
||||
Args: Args{Method: "Post", URL: "/settings", Data: map[string]interface{}{"artifactKinds": []interface{}{map[string]interface{}{"icon": "mdi-server", "id": "asset", "name": "Asset"}, map[string]interface{}{"icon": "mdi-bullseye", "id": "ioc", "name": "IOC"}}, "artifactStates": []interface{}{map[string]interface{}{"color": "info", "icon": "mdi-help-circle-outline", "id": "unknown", "name": "Unknown"}, map[string]interface{}{"color": "error", "icon": "mdi-skull", "id": "malicious", "name": "Malicious"}, map[string]interface{}{"color": "success", "icon": "mdi-check", "id": "clean", "name": "Clean"}}, "timeformat": "yyyy-MM-dd hh:mm:ss"}},
|
||||
Want: Want{
|
||||
Status: 200,
|
||||
Body: map[string]interface{}{"artifactKinds": []interface{}{map[string]interface{}{"icon": "mdi-server", "id": "asset", "name": "Asset"}, map[string]interface{}{"icon": "mdi-bullseye", "id": "ioc", "name": "IOC"}}, "artifactStates": []interface{}{map[string]interface{}{"color": "info", "icon": "mdi-help-circle-outline", "id": "unknown", "name": "Unknown"}, map[string]interface{}{"color": "error", "icon": "mdi-skull", "id": "malicious", "name": "Malicious"}, map[string]interface{}{"color": "success", "icon": "mdi-check", "id": "clean", "name": "Clean"}}, "roles": []interface{}{"admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write"}, "ticketTypes": []interface{}{map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-alert", "id": "alert", "name": "Alerts"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-radioactive", "id": "incident", "name": "Incidents"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-fingerprint", "id": "investigation", "name": "Forensic Investigations"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-target", "id": "hunt", "name": "Threat Hunting"}}, "tier": "community", "timeformat": "yyyy-MM-dd hh:mm:ss", "version": "0.0.0-test"},
|
||||
Body: map[string]interface{}{"artifactKinds": []interface{}{map[string]interface{}{"icon": "mdi-server", "id": "asset", "name": "Asset"}, map[string]interface{}{"icon": "mdi-bullseye", "id": "ioc", "name": "IOC"}}, "artifactStates": []interface{}{map[string]interface{}{"color": "info", "icon": "mdi-help-circle-outline", "id": "unknown", "name": "Unknown"}, map[string]interface{}{"color": "error", "icon": "mdi-skull", "id": "malicious", "name": "Malicious"}, map[string]interface{}{"color": "success", "icon": "mdi-check", "id": "clean", "name": "Clean"}}, "ticketTypes": []interface{}{map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-alert", "id": "alert", "name": "Alerts"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-radioactive", "id": "incident", "name": "Incidents"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-fingerprint", "id": "investigation", "name": "Forensic Investigations"}, map[string]interface{}{"default_playbooks": []interface{}{}, "default_template": "default", "icon": "mdi-target", "id": "hunt", "name": "Threat Hunting"}}, "tier": "community", "timeformat": "yyyy-MM-dd hh:mm:ss", "version": "0.0.0-test"},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -608,7 +608,7 @@ var Tests = []struct {
|
||||
Args: Args{Method: "Get", URL: "/users"},
|
||||
Want: Want{
|
||||
Status: 200,
|
||||
Body: []interface{}{map[string]interface{}{"apikey": false, "blocked": false, "id": "bob", "roles": []interface{}{"admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write"}}, map[string]interface{}{"apikey": true, "blocked": false, "id": "script", "roles": []interface{}{"analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write"}}},
|
||||
Body: []interface{}{map[string]interface{}{"apikey": false, "blocked": false, "id": "bob", "roles": []interface{}{"admin"}}, map[string]interface{}{"apikey": true, "blocked": false, "id": "script", "roles": []interface{}{"engineer"}}},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -617,7 +617,7 @@ var Tests = []struct {
|
||||
Args: Args{Method: "Post", URL: "/users", Data: map[string]interface{}{"apikey": true, "blocked": false, "id": "syncscript", "roles": []interface{}{"analyst"}}},
|
||||
Want: Want{
|
||||
Status: 200,
|
||||
Body: map[string]interface{}{"blocked": false, "id": "syncscript", "roles": []interface{}{"analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read"}, "secret": "v39bOuobnlEljfWzjAgoKzhmnh1xSMxH"},
|
||||
Body: map[string]interface{}{"blocked": false, "id": "syncscript", "roles": []interface{}{"analyst"}, "secret": "v39bOuobnlEljfWzjAgoKzhmnh1xSMxH"},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -626,7 +626,7 @@ var Tests = []struct {
|
||||
Args: Args{Method: "Get", URL: "/users/script"},
|
||||
Want: Want{
|
||||
Status: 200,
|
||||
Body: map[string]interface{}{"apikey": true, "blocked": false, "id": "script", "roles": []interface{}{"analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write"}},
|
||||
Body: map[string]interface{}{"apikey": true, "blocked": false, "id": "script", "roles": []interface{}{"engineer"}},
|
||||
},
|
||||
},
|
||||
|
||||
@@ -635,7 +635,7 @@ var Tests = []struct {
|
||||
Args: Args{Method: "Put", URL: "/users/bob", Data: map[string]interface{}{"apikey": false, "blocked": false, "id": "syncscript", "roles": []interface{}{"analyst", "admin"}}},
|
||||
Want: Want{
|
||||
Status: 200,
|
||||
Body: map[string]interface{}{"apikey": false, "blocked": false, "id": "bob", "roles": []interface{}{"admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write"}},
|
||||
Body: map[string]interface{}{"apikey": false, "blocked": false, "id": "bob", "roles": []interface{}{"analyst", "admin"}},
|
||||
},
|
||||
},
|
||||
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
"apikey" : false,
|
||||
"blocked" : false,
|
||||
"id" : "bob",
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "admin" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -1424,7 +1424,6 @@
|
||||
"id" : "clean",
|
||||
"name" : "Clean"
|
||||
} ],
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ],
|
||||
"ticketTypes" : [ {
|
||||
"default_playbooks" : [ ],
|
||||
"default_template" : "default",
|
||||
@@ -1513,7 +1512,6 @@
|
||||
"id" : "clean",
|
||||
"name" : "Clean"
|
||||
} ],
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ],
|
||||
"ticketTypes" : [ {
|
||||
"default_playbooks" : [ ],
|
||||
"default_template" : "default",
|
||||
@@ -5343,12 +5341,12 @@
|
||||
"apikey" : false,
|
||||
"blocked" : false,
|
||||
"id" : "bob",
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "admin" ]
|
||||
}, {
|
||||
"apikey" : true,
|
||||
"blocked" : false,
|
||||
"id" : "script",
|
||||
"roles" : [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "engineer" ]
|
||||
} ]
|
||||
}
|
||||
},
|
||||
@@ -5386,7 +5384,7 @@
|
||||
"example" : {
|
||||
"blocked" : false,
|
||||
"id" : "syncscript",
|
||||
"roles" : [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read" ],
|
||||
"roles" : [ "analyst" ],
|
||||
"secret" : "v39bOuobnlEljfWzjAgoKzhmnh1xSMxH"
|
||||
}
|
||||
}
|
||||
@@ -5452,7 +5450,7 @@
|
||||
"apikey" : true,
|
||||
"blocked" : false,
|
||||
"id" : "script",
|
||||
"roles" : [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "engineer" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5501,7 +5499,7 @@
|
||||
"apikey" : false,
|
||||
"blocked" : false,
|
||||
"id" : "bob",
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "analyst", "admin" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1631,38 +1631,7 @@ paths:
|
||||
blocked: false
|
||||
id: bob
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- admin
|
||||
schema:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
security:
|
||||
@@ -2834,39 +2803,6 @@ paths:
|
||||
icon: mdi-check
|
||||
id: clean
|
||||
name: Clean
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
ticketTypes:
|
||||
- default_playbooks: []
|
||||
default_template: default
|
||||
@@ -2955,39 +2891,6 @@ paths:
|
||||
icon: mdi-check
|
||||
id: clean
|
||||
name: Clean
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
ticketTypes:
|
||||
- default_playbooks: []
|
||||
default_template: default
|
||||
@@ -7360,62 +7263,12 @@ paths:
|
||||
blocked: false
|
||||
id: bob
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- admin
|
||||
- apikey: true
|
||||
blocked: false
|
||||
id: script
|
||||
roles:
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- engineer
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
@@ -7449,21 +7302,7 @@ paths:
|
||||
blocked: false
|
||||
id: syncscript
|
||||
roles:
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- analyst
|
||||
secret: v39bOuobnlEljfWzjAgoKzhmnh1xSMxH
|
||||
schema:
|
||||
$ref: '#/definitions/NewUserResponse'
|
||||
@@ -7510,26 +7349,7 @@ paths:
|
||||
blocked: false
|
||||
id: script
|
||||
roles:
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- engineer
|
||||
schema:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
security:
|
||||
@@ -7569,38 +7389,8 @@ paths:
|
||||
blocked: false
|
||||
id: bob
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- analyst
|
||||
- admin
|
||||
schema:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
security:
|
||||
|
||||
@@ -225,7 +225,7 @@
|
||||
"apikey" : false,
|
||||
"blocked" : false,
|
||||
"id" : "bob",
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "admin" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -994,7 +994,6 @@
|
||||
"id" : "clean",
|
||||
"name" : "Clean"
|
||||
} ],
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ],
|
||||
"ticketTypes" : [ {
|
||||
"default_playbooks" : [ ],
|
||||
"default_template" : "default",
|
||||
@@ -1083,7 +1082,6 @@
|
||||
"id" : "clean",
|
||||
"name" : "Clean"
|
||||
} ],
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ],
|
||||
"ticketTypes" : [ {
|
||||
"default_playbooks" : [ ],
|
||||
"default_template" : "default",
|
||||
@@ -4913,12 +4911,12 @@
|
||||
"apikey" : false,
|
||||
"blocked" : false,
|
||||
"id" : "bob",
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "admin" ]
|
||||
}, {
|
||||
"apikey" : true,
|
||||
"blocked" : false,
|
||||
"id" : "script",
|
||||
"roles" : [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "engineer" ]
|
||||
} ]
|
||||
}
|
||||
},
|
||||
@@ -4956,7 +4954,7 @@
|
||||
"example" : {
|
||||
"blocked" : false,
|
||||
"id" : "syncscript",
|
||||
"roles" : [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read" ],
|
||||
"roles" : [ "analyst" ],
|
||||
"secret" : "v39bOuobnlEljfWzjAgoKzhmnh1xSMxH"
|
||||
}
|
||||
}
|
||||
@@ -5022,7 +5020,7 @@
|
||||
"apikey" : true,
|
||||
"blocked" : false,
|
||||
"id" : "script",
|
||||
"roles" : [ "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "engineer" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
@@ -5071,7 +5069,7 @@
|
||||
"apikey" : false,
|
||||
"blocked" : false,
|
||||
"id" : "bob",
|
||||
"roles" : [ "admin:backup:read", "admin:backup:restore", "admin:dashboard:write", "admin:group:write", "admin:job:read", "admin:job:write", "admin:log:read", "admin:settings:write", "admin:ticket:delete", "admin:user:write", "admin:userdata:read", "admin:userdata:write", "analyst:automation:read", "analyst:currentsettings:write", "analyst:currentuser:read", "analyst:currentuserdata:read", "analyst:dashboard:read", "analyst:file", "analyst:group:read", "analyst:playbook:read", "analyst:rule:read", "analyst:settings:read", "analyst:template:read", "analyst:ticket:read", "analyst:ticket:write", "analyst:tickettype:read", "analyst:user:read", "engineer:automation:write", "engineer:playbook:write", "engineer:rule:write", "engineer:template:write", "engineer:tickettype:write" ]
|
||||
"roles" : [ "analyst", "admin" ]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
@@ -1512,38 +1512,7 @@ paths:
|
||||
blocked: false
|
||||
id: bob
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- admin
|
||||
schema:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
security:
|
||||
@@ -2422,39 +2391,6 @@ paths:
|
||||
icon: mdi-check
|
||||
id: clean
|
||||
name: Clean
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
ticketTypes:
|
||||
- default_playbooks: []
|
||||
default_template: default
|
||||
@@ -2543,39 +2479,6 @@ paths:
|
||||
icon: mdi-check
|
||||
id: clean
|
||||
name: Clean
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
ticketTypes:
|
||||
- default_playbooks: []
|
||||
default_template: default
|
||||
@@ -6948,62 +6851,12 @@ paths:
|
||||
blocked: false
|
||||
id: bob
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- admin
|
||||
- apikey: true
|
||||
blocked: false
|
||||
id: script
|
||||
roles:
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- engineer
|
||||
schema:
|
||||
items:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
@@ -7037,21 +6890,7 @@ paths:
|
||||
blocked: false
|
||||
id: syncscript
|
||||
roles:
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- analyst
|
||||
secret: v39bOuobnlEljfWzjAgoKzhmnh1xSMxH
|
||||
schema:
|
||||
$ref: '#/definitions/NewUserResponse'
|
||||
@@ -7098,26 +6937,7 @@ paths:
|
||||
blocked: false
|
||||
id: script
|
||||
roles:
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- engineer
|
||||
schema:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
security:
|
||||
@@ -7157,38 +6977,8 @@ paths:
|
||||
blocked: false
|
||||
id: bob
|
||||
roles:
|
||||
- admin:backup:read
|
||||
- admin:backup:restore
|
||||
- admin:dashboard:write
|
||||
- admin:group:write
|
||||
- admin:job:read
|
||||
- admin:job:write
|
||||
- admin:log:read
|
||||
- admin:settings:write
|
||||
- admin:ticket:delete
|
||||
- admin:user:write
|
||||
- admin:userdata:read
|
||||
- admin:userdata:write
|
||||
- analyst:automation:read
|
||||
- analyst:currentsettings:write
|
||||
- analyst:currentuser:read
|
||||
- analyst:currentuserdata:read
|
||||
- analyst:dashboard:read
|
||||
- analyst:file
|
||||
- analyst:group:read
|
||||
- analyst:playbook:read
|
||||
- analyst:rule:read
|
||||
- analyst:settings:read
|
||||
- analyst:template:read
|
||||
- analyst:ticket:read
|
||||
- analyst:ticket:write
|
||||
- analyst:tickettype:read
|
||||
- analyst:user:read
|
||||
- engineer:automation:write
|
||||
- engineer:playbook:write
|
||||
- engineer:rule:write
|
||||
- engineer:template:write
|
||||
- engineer:tickettype:write
|
||||
- analyst
|
||||
- admin
|
||||
schema:
|
||||
$ref: '#/definitions/UserResponse'
|
||||
security:
|
||||
|
||||
122
go.cap
122
go.cap
@@ -1,122 +0,0 @@
|
||||
github.com/SecurityBrewery/catalyst/cmd/catalyst (network)
|
||||
|
||||
github.com/RoaringBitmap/roaring (reflect, unsafe)
|
||||
github.com/SecurityBrewery/catalyst (execute, file, network)
|
||||
github.com/SecurityBrewery/catalyst/auth (network)
|
||||
github.com/SecurityBrewery/catalyst/database/busdb (network)
|
||||
github.com/SecurityBrewery/catalyst/generated/api (network)
|
||||
github.com/SecurityBrewery/catalyst/index (file)
|
||||
github.com/SecurityBrewery/catalyst/service (network)
|
||||
github.com/alecthomas/kong (file, reflect, syscall, unsafe)
|
||||
github.com/antlr/antlr4/runtime/Go/antlr (file, reflect)
|
||||
github.com/arangodb/go-driver (file, network, reflect)
|
||||
github.com/arangodb/go-driver/cluster (network)
|
||||
github.com/arangodb/go-driver/http (file, network, reflect)
|
||||
github.com/arangodb/go-velocypack (reflect)
|
||||
github.com/aws/aws-sdk-go/aws (file, network)
|
||||
github.com/aws/aws-sdk-go/aws/awsutil (reflect)
|
||||
github.com/aws/aws-sdk-go/aws/client (file)
|
||||
github.com/aws/aws-sdk-go/aws/corehandlers (file, network)
|
||||
github.com/aws/aws-sdk-go/aws/credentials (file)
|
||||
github.com/aws/aws-sdk-go/aws/credentials/processcreds (execute, file)
|
||||
github.com/aws/aws-sdk-go/aws/credentials/ssocreds (file)
|
||||
github.com/aws/aws-sdk-go/aws/credentials/stscreds (file)
|
||||
github.com/aws/aws-sdk-go/aws/csm (network)
|
||||
github.com/aws/aws-sdk-go/aws/defaults (file, network)
|
||||
github.com/aws/aws-sdk-go/aws/ec2metadata (file, network)
|
||||
github.com/aws/aws-sdk-go/aws/request (file, network, reflect)
|
||||
github.com/aws/aws-sdk-go/aws/session (file, network)
|
||||
github.com/aws/aws-sdk-go/aws/signer/v4 (file, network)
|
||||
github.com/aws/aws-sdk-go/internal/ini (file)
|
||||
github.com/aws/aws-sdk-go/internal/shareddefaults (file)
|
||||
github.com/aws/aws-sdk-go/private/protocol (file, network, reflect)
|
||||
github.com/aws/aws-sdk-go/private/protocol/json/jsonutil (reflect)
|
||||
github.com/aws/aws-sdk-go/private/protocol/jsonrpc (file, network)
|
||||
github.com/aws/aws-sdk-go/private/protocol/query/queryutil (reflect)
|
||||
github.com/aws/aws-sdk-go/private/protocol/rest (file, network, reflect)
|
||||
github.com/aws/aws-sdk-go/private/protocol/restjson (file, network)
|
||||
github.com/aws/aws-sdk-go/private/protocol/xml/xmlutil (reflect)
|
||||
github.com/aws/aws-sdk-go/service/s3 (file, network)
|
||||
github.com/aws/aws-sdk-go/service/s3/s3manager (network)
|
||||
github.com/blevesearch/bleve/v2 (file, reflect)
|
||||
github.com/blevesearch/bleve/v2/analysis (file)
|
||||
github.com/blevesearch/bleve/v2/document (network, reflect)
|
||||
github.com/blevesearch/bleve/v2/geo (reflect)
|
||||
github.com/blevesearch/bleve/v2/index/scorch (file, reflect)
|
||||
github.com/blevesearch/bleve/v2/index/upsidedown (reflect)
|
||||
github.com/blevesearch/bleve/v2/index/upsidedown/store/boltdb (file)
|
||||
github.com/blevesearch/bleve/v2/index/upsidedown/store/gtreap (file)
|
||||
github.com/blevesearch/bleve/v2/mapping (file, network, reflect)
|
||||
github.com/blevesearch/bleve/v2/search (reflect)
|
||||
github.com/blevesearch/bleve/v2/search/collector (reflect)
|
||||
github.com/blevesearch/bleve/v2/search/facet (reflect)
|
||||
github.com/blevesearch/bleve/v2/search/highlight (reflect)
|
||||
github.com/blevesearch/bleve/v2/search/query (file, network)
|
||||
github.com/blevesearch/bleve/v2/search/scorer (reflect)
|
||||
github.com/blevesearch/bleve/v2/search/searcher (network, reflect)
|
||||
github.com/blevesearch/bleve/v2/size (reflect)
|
||||
github.com/blevesearch/bleve_index_api (reflect)
|
||||
github.com/blevesearch/mmap-go (file, reflect, unsafe)
|
||||
github.com/blevesearch/vellum (file)
|
||||
github.com/blevesearch/zapx/v11 (file, reflect, unsafe)
|
||||
github.com/blevesearch/zapx/v12 (file, reflect, unsafe)
|
||||
github.com/blevesearch/zapx/v13 (file, reflect, unsafe)
|
||||
github.com/blevesearch/zapx/v14 (file, reflect, unsafe)
|
||||
github.com/blevesearch/zapx/v15 (file, reflect, unsafe)
|
||||
github.com/bmizerany/pat (network)
|
||||
github.com/coreos/go-oidc/v3/oidc (file, network)
|
||||
github.com/docker/distribution/registry/api/errcode (network)
|
||||
github.com/docker/docker/api/types (file, network)
|
||||
github.com/docker/docker/api/types/mount (file)
|
||||
github.com/docker/docker/api/types/registry (network)
|
||||
github.com/docker/docker/api/types/swarm (file)
|
||||
github.com/docker/docker/client (file, network)
|
||||
github.com/docker/docker/errdefs (network)
|
||||
github.com/docker/go-connections/nat (network)
|
||||
github.com/docker/go-connections/sockets (file, network, syscall)
|
||||
github.com/docker/go-connections/tlsconfig (file)
|
||||
github.com/go-chi/chi/v5 (network)
|
||||
github.com/go-chi/chi/v5/middleware (file, network)
|
||||
github.com/gobwas/ws (network, reflect, unsafe)
|
||||
github.com/gobwas/ws/wsutil (file, network)
|
||||
github.com/gogo/protobuf/proto (reflect, unsafe)
|
||||
github.com/golang/protobuf/proto (file, reflect)
|
||||
github.com/golang/protobuf/ptypes/any (reflect)
|
||||
github.com/golang/protobuf/ptypes/duration (reflect)
|
||||
github.com/golang/protobuf/ptypes/timestamp (reflect)
|
||||
github.com/google/uuid (file, network)
|
||||
github.com/imdario/mergo (reflect)
|
||||
github.com/jmespath/go-jmespath (reflect)
|
||||
github.com/sirupsen/logrus (file, reflect)
|
||||
github.com/tus/tusd/pkg/handler (file, network)
|
||||
github.com/tus/tusd/pkg/s3store (file, network)
|
||||
github.com/xeipuuv/gojsonpointer (reflect)
|
||||
github.com/xeipuuv/gojsonschema (file, network, reflect)
|
||||
go.etcd.io/bbolt (file, reflect, syscall, unsafe)
|
||||
golang.org/x/net/context/ctxhttp (network)
|
||||
golang.org/x/net/internal/socks (network)
|
||||
golang.org/x/net/proxy (file, network)
|
||||
golang.org/x/oauth2 (network)
|
||||
golang.org/x/oauth2/internal (file, network)
|
||||
golang.org/x/sys/cpu (file)
|
||||
golang.org/x/sys/internal/unsafeheader (unsafe)
|
||||
golang.org/x/sys/unix (syscall, unsafe)
|
||||
google.golang.org/genproto/googleapis/rpc/status (reflect)
|
||||
google.golang.org/protobuf/internal/descfmt (reflect)
|
||||
google.golang.org/protobuf/internal/detrand (file)
|
||||
google.golang.org/protobuf/internal/encoding/tag (reflect)
|
||||
google.golang.org/protobuf/internal/filedesc (reflect)
|
||||
google.golang.org/protobuf/internal/filetype (reflect)
|
||||
google.golang.org/protobuf/internal/impl (file, reflect, unsafe)
|
||||
google.golang.org/protobuf/internal/strs (unsafe)
|
||||
google.golang.org/protobuf/proto (reflect)
|
||||
google.golang.org/protobuf/reflect/protoreflect (unsafe)
|
||||
google.golang.org/protobuf/reflect/protoregistry (file)
|
||||
google.golang.org/protobuf/types/descriptorpb (reflect)
|
||||
google.golang.org/protobuf/types/known/anypb (reflect)
|
||||
google.golang.org/protobuf/types/known/durationpb (reflect)
|
||||
google.golang.org/protobuf/types/known/timestamppb (reflect)
|
||||
gopkg.in/square/go-jose.v2 (reflect)
|
||||
gopkg.in/square/go-jose.v2/json (reflect)
|
||||
gopkg.in/yaml.v2 (reflect)
|
||||
gopkg.in/yaml.v3 (reflect)
|
||||
19
go.mod
19
go.mod
@@ -2,6 +2,8 @@ module github.com/SecurityBrewery/catalyst
|
||||
|
||||
go 1.19
|
||||
|
||||
replace github.com/xeipuuv/gojsonschema => github.com/warjiang/gojsonschema v1.2.1-0.20210329105853-aa9f9a8cfec7
|
||||
|
||||
require (
|
||||
github.com/alecthomas/kong v0.6.1
|
||||
github.com/alecthomas/kong-yaml v0.1.1
|
||||
@@ -14,18 +16,17 @@ require (
|
||||
github.com/go-chi/chi/v5 v5.0.7
|
||||
github.com/gobwas/ws v1.1.0
|
||||
github.com/google/uuid v1.3.0
|
||||
github.com/gorilla/securecookie v1.1.1
|
||||
github.com/iancoleman/strcase v0.2.0
|
||||
github.com/icza/dyno v0.0.0-20220812133438-f0b6f8a18845
|
||||
github.com/imdario/mergo v0.3.13
|
||||
github.com/jonas-plum/maut v0.0.0-20221001191853-1856efe6da0b
|
||||
github.com/mingrammer/commonregex v1.0.1
|
||||
github.com/stretchr/testify v1.8.0
|
||||
github.com/tidwall/gjson v1.14.3
|
||||
github.com/tidwall/sjson v1.2.5
|
||||
github.com/tus/tusd v1.9.2
|
||||
github.com/xeipuuv/gojsonschema v1.2.0
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9
|
||||
golang.org/x/exp v0.0.0-20220929160808-de9c53c655b9
|
||||
golang.org/x/oauth2 v0.0.0-20220909003341-f21342109be1
|
||||
gopkg.in/yaml.v3 v3.0.1
|
||||
)
|
||||
@@ -61,24 +62,24 @@ require (
|
||||
github.com/gogo/protobuf v1.3.2 // indirect
|
||||
github.com/golang/protobuf v1.5.2 // indirect
|
||||
github.com/golang/snappy v0.0.4 // indirect
|
||||
github.com/gorilla/mux v1.8.0 // indirect
|
||||
github.com/gorilla/securecookie v1.1.1 // indirect
|
||||
github.com/gorilla/sessions v1.2.1 // indirect
|
||||
github.com/jmespath/go-jmespath v0.4.0 // indirect
|
||||
github.com/kr/pretty v0.3.0 // indirect
|
||||
github.com/morikuni/aec v1.0.0 // indirect
|
||||
github.com/mschoch/smat v0.2.0 // indirect
|
||||
github.com/opencontainers/go-digest v1.0.0 // indirect
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
|
||||
github.com/pkg/errors v0.9.1 // indirect
|
||||
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||
github.com/rogpeppe/go-internal v1.8.0 // indirect
|
||||
github.com/sirupsen/logrus v1.8.1 // indirect
|
||||
github.com/sirupsen/logrus v1.9.0 // indirect
|
||||
github.com/tidwall/match v1.1.1 // indirect
|
||||
github.com/tidwall/pretty v1.2.0 // indirect
|
||||
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
|
||||
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
|
||||
go.etcd.io/bbolt v1.3.6 // indirect
|
||||
golang.org/x/crypto v0.0.0-20220926161630-eccd6366d1be // indirect
|
||||
golang.org/x/net v0.0.0-20220826154423-83b083e8dc8b // indirect
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab // indirect
|
||||
google.golang.org/appengine v1.6.7 // indirect
|
||||
google.golang.org/genproto v0.0.0-20220810155839-1856144b1d9c // indirect
|
||||
google.golang.org/grpc v1.49.0 // indirect
|
||||
@@ -87,5 +88,3 @@ require (
|
||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||
gotest.tools v2.2.0+incompatible // indirect
|
||||
)
|
||||
|
||||
replace github.com/xeipuuv/gojsonschema => github.com/warjiang/gojsonschema v1.2.1-0.20210329105853-aa9f9a8cfec7
|
||||
|
||||
33
go.sum
33
go.sum
@@ -168,7 +168,6 @@ github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7
|
||||
github.com/couchbase/ghistogram v0.1.0/go.mod h1:s1Jhy76zqfEecpNWJfWUiKZookAFaiGOEoyzgHt9i7k=
|
||||
github.com/couchbase/moss v0.2.0/go.mod h1:9MaHIaRuy9pvLPUJxB8sh8OrLfyDczECVL37grCIubs=
|
||||
github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE=
|
||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||
@@ -191,6 +190,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
|
||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||
github.com/envoyproxy/go-control-plane v0.10.2-0.20220325020618-49ff273808a1/go.mod h1:KJwIaB5Mv44NWtYuAOFCVOjcI94vtpEz2JU/D2v6IjE=
|
||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
|
||||
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||
@@ -305,10 +305,13 @@ github.com/googleapis/gax-go/v2 v2.2.0/go.mod h1:as02EH8zWkzwUoLbBaFeQ+arQaj/Oth
|
||||
github.com/googleapis/gax-go/v2 v2.3.0/go.mod h1:b8LNqSzNabLiUpXKkY7HAR5jr6bIT99EXz9pXxye9YM=
|
||||
github.com/googleapis/gax-go/v2 v2.4.0/go.mod h1:XOTVJ59hdnfJLIP/dh8n5CGryZR2LxK9wbMD5+iXC6c=
|
||||
github.com/googleapis/go-type-adapters v1.0.0/go.mod h1:zHW75FOG2aur7gAO2B+MLby+cLsWGBF62rFAi7WjWO4=
|
||||
github.com/gorilla/handlers v1.5.1 h1:9lRY6j8DEeeBT10CvO9hGW0gmky0BprnvDI5vfhUHH4=
|
||||
github.com/gorilla/mux v1.8.0 h1:i40aqfkR1h2SlN9hojwV5ZA91wcXFOvkdNIeFDP5koI=
|
||||
github.com/gorilla/mux v1.8.0/go.mod h1:DVbg23sWSpFRCP0SfiEN6jmj59UnW/n46BH5rLB71So=
|
||||
github.com/gorilla/schema v1.2.0 h1:YufUaxZYCKGFuAq3c96BOhjgd5nmXiOY9NGzF247Tsc=
|
||||
github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ=
|
||||
github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4=
|
||||
github.com/gorilla/sessions v1.2.1 h1:DHd3rPN5lE3Ts3D8rKkQ8x/0kqfeNmBAaiSi+o7FsgI=
|
||||
github.com/gorilla/sessions v1.2.1/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
|
||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
||||
github.com/h2non/parth v0.0.0-20190131123155-b4df798d6542/go.mod h1:Ow0tF8D4Kplbc8s8sSb3V2oUCygFHVp8gC3Dn6U4MNI=
|
||||
@@ -329,6 +332,8 @@ github.com/jmespath/go-jmespath v0.4.0 h1:BEgLn5cpjn8UN1mAw4NjwDrS35OdebyEtFe+9Y
|
||||
github.com/jmespath/go-jmespath v0.4.0/go.mod h1:T8mJZnbsbmF+m6zOOFylbeCJqk5+pHWvzYPziyZiYoo=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1 h1:shLQSRRSCCPj3f2gpwzGwWFoC7ycTf1rcQZHOlsJ6N8=
|
||||
github.com/jmespath/go-jmespath/internal/testify v1.5.1/go.mod h1:L3OGu8Wl2/fWfCI6z80xFu9LTZmf1ZRjMHUOPmWr69U=
|
||||
github.com/jonas-plum/maut v0.0.0-20221001191853-1856efe6da0b h1:gJtcxg/ifOIf7eWXv0ETHYUCEYLxo29WK7RKF+vJ/a4=
|
||||
github.com/jonas-plum/maut v0.0.0-20221001191853-1856efe6da0b/go.mod h1:GHi17CboIfEAzcLKyOforrRGpNsJkIahosnrlgfsOvM=
|
||||
github.com/jpillora/backoff v1.0.0/go.mod h1:J/6gKK9jxlEcS3zixgDgUAsiuZ7yrSoa/FX5e0EB2j4=
|
||||
github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU=
|
||||
github.com/json-iterator/go v1.1.10/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||
@@ -344,13 +349,11 @@ github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxv
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
|
||||
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
|
||||
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/mattn/go-ieproxy v0.0.1/go.mod h1:pYabZ6IHcRpFh7vIaLfK7rdcWgFEb3SFJ6/gNWuh88E=
|
||||
github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0=
|
||||
@@ -379,7 +382,6 @@ github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 h1:rc3
|
||||
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0=
|
||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||
@@ -406,9 +408,6 @@ github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1
|
||||
github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA=
|
||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
|
||||
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
|
||||
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
|
||||
github.com/rs/zerolog v1.19.0/go.mod h1:IzD0RJ65iWH0w97OQQebJEvTZYvsCUm9WVLWBQrJRjo=
|
||||
github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g=
|
||||
@@ -417,8 +416,8 @@ github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPx
|
||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
|
||||
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
||||
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
|
||||
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
|
||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||
@@ -465,6 +464,8 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
||||
github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||
github.com/zitadel/logging v0.3.4 h1:9hZsTjMMTE3X2LUi0xcF9Q9EdLo+FAezeu52ireBbHM=
|
||||
github.com/zitadel/oidc v1.8.0 h1:FEUuAaZVgZv0dWGpCNcG1ov7COVDA5x2yzlYwqy8iTs=
|
||||
go.etcd.io/bbolt v1.3.5/go.mod h1:G5EMThwa9y8QZGBClrRx5EY+Yw9kAhnjy3bSjsnlVTQ=
|
||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
||||
@@ -499,8 +500,8 @@ golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u0
|
||||
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
|
||||
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
|
||||
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9 h1:RjggHMcaTVp0LOVZcW0bo8alwHrOaCrGUDgfWUHhnN4=
|
||||
golang.org/x/exp v0.0.0-20220930202632-ec3f01382ef9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/exp v0.0.0-20220929160808-de9c53c655b9 h1:lNtcVz/3bOstm7Vebox+5m3nLh/BYWnhmc3AhXOW6oI=
|
||||
golang.org/x/exp v0.0.0-20220929160808-de9c53c655b9/go.mod h1:cyybsKvd6eL0RnXn6p/Grxp8F5bW7iYuBgsNCOHpMYE=
|
||||
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
|
||||
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
|
||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
||||
@@ -687,8 +688,10 @@ golang.org/x/sys v0.0.0-20220503163025-988cb79eb6c6/go.mod h1:oPkhp1MJrh7nUepCBc
|
||||
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220610221304-9f5ed59c137d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220624220833-87e55d714810/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 h1:WIoqL4EROvwiPdUtaip4VcDdpZ4kha7wBWZrbVKCIZg=
|
||||
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab h1:2QkjZIsXupsJbJIdSjjUOgWK3aEtzyuh2mPt3l/CkeU=
|
||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
||||
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
|
||||
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
|
||||
171
role/role.go
171
role/role.go
@@ -1,171 +0,0 @@
|
||||
package role
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/exp/slices"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
)
|
||||
|
||||
type Role string
|
||||
|
||||
const (
|
||||
Analyst string = "analyst"
|
||||
Engineer string = "engineer"
|
||||
Admin string = "admin"
|
||||
|
||||
AutomationRead Role = "analyst:automation:read"
|
||||
CurrentuserRead Role = "analyst:currentuser:read"
|
||||
CurrentuserdataRead Role = "analyst:currentuserdata:read"
|
||||
CurrentuserdataWrite Role = "analyst:currentsettings:write"
|
||||
DashboardRead Role = "analyst:dashboard:read"
|
||||
FileReadWrite Role = "analyst:file"
|
||||
GroupRead Role = "analyst:group:read"
|
||||
PlaybookRead Role = "analyst:playbook:read"
|
||||
RuleRead Role = "analyst:rule:read"
|
||||
SettingsRead Role = "analyst:settings:read"
|
||||
TemplateRead Role = "analyst:template:read"
|
||||
TicketRead Role = "analyst:ticket:read"
|
||||
TicketWrite Role = "analyst:ticket:write"
|
||||
TickettypeRead Role = "analyst:tickettype:read"
|
||||
UserRead Role = "analyst:user:read"
|
||||
|
||||
AutomationWrite Role = "engineer:automation:write"
|
||||
PlaybookWrite Role = "engineer:playbook:write"
|
||||
RuleWrite Role = "engineer:rule:write"
|
||||
TemplateWrite Role = "engineer:template:write"
|
||||
TickettypeWrite Role = "engineer:tickettype:write"
|
||||
|
||||
BackupRead Role = "admin:backup:read"
|
||||
BackupRestore Role = "admin:backup:restore"
|
||||
DashboardWrite Role = "admin:dashboard:write"
|
||||
GroupWrite Role = "admin:group:write"
|
||||
JobRead Role = "admin:job:read"
|
||||
JobWrite Role = "admin:job:write"
|
||||
LogRead Role = "admin:log:read"
|
||||
SettingsWrite Role = "admin:settings:write"
|
||||
TicketDelete Role = "admin:ticket:delete"
|
||||
UserWrite Role = "admin:user:write"
|
||||
UserdataRead Role = "admin:userdata:read"
|
||||
UserdataWrite Role = "admin:userdata:write"
|
||||
)
|
||||
|
||||
func (p Role) String() string {
|
||||
return string(p)
|
||||
}
|
||||
|
||||
func UserHasRoles(user *model.UserResponse, roles []Role) bool {
|
||||
hasRoles := true
|
||||
for _, role := range roles {
|
||||
if !UserHasRole(user, role) {
|
||||
hasRoles = false
|
||||
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return hasRoles
|
||||
}
|
||||
|
||||
func UserHasRole(user *model.UserResponse, role Role) bool {
|
||||
return slices.Contains(FromStrings(user.Roles), role)
|
||||
}
|
||||
|
||||
func Explodes(s []string) []Role {
|
||||
var roles []Role
|
||||
for _, e := range s {
|
||||
roles = append(roles, Explode(e)...)
|
||||
}
|
||||
sort.Slice(roles, func(i, j int) bool {
|
||||
return roles[i].String() < roles[j].String()
|
||||
})
|
||||
roles = slices.Compact(roles)
|
||||
|
||||
return roles
|
||||
}
|
||||
|
||||
func Explode(s string) []Role {
|
||||
var roles []Role
|
||||
|
||||
switch s {
|
||||
case Admin:
|
||||
roles = append(roles, listPrefix(Admin)...)
|
||||
|
||||
fallthrough
|
||||
case Engineer:
|
||||
roles = append(roles, listPrefix(Engineer)...)
|
||||
|
||||
fallthrough
|
||||
case Analyst:
|
||||
roles = append(roles, listPrefix(Analyst)...)
|
||||
|
||||
return roles
|
||||
}
|
||||
|
||||
for _, role := range List() {
|
||||
if role.String() == s {
|
||||
roles = append(roles, role)
|
||||
}
|
||||
}
|
||||
|
||||
return roles
|
||||
}
|
||||
|
||||
func listPrefix(s string) []Role {
|
||||
var roles []Role
|
||||
|
||||
for _, role := range List() {
|
||||
if strings.HasPrefix(role.String(), s+":") {
|
||||
roles = append(roles, role)
|
||||
}
|
||||
}
|
||||
|
||||
return roles
|
||||
}
|
||||
|
||||
func List() []Role {
|
||||
return []Role{
|
||||
AutomationRead, CurrentuserdataRead, CurrentuserdataWrite,
|
||||
CurrentuserRead, FileReadWrite, GroupRead, PlaybookRead, RuleRead,
|
||||
UserdataRead, SettingsRead, TemplateRead, TicketRead, TickettypeRead,
|
||||
TicketWrite, UserRead, AutomationWrite, PlaybookWrite, RuleWrite,
|
||||
TemplateWrite, TickettypeWrite, BackupRead, BackupRestore, GroupWrite,
|
||||
LogRead, UserdataWrite, TicketDelete, UserWrite, JobRead, JobWrite,
|
||||
SettingsWrite, DashboardRead, DashboardWrite,
|
||||
}
|
||||
}
|
||||
|
||||
func fromString(s string) (Role, error) {
|
||||
for _, role := range List() {
|
||||
if role.String() == s {
|
||||
return role, nil
|
||||
}
|
||||
}
|
||||
|
||||
return "", errors.New("unknown role")
|
||||
}
|
||||
|
||||
func Strings(roles []Role) []string {
|
||||
var s []string
|
||||
for _, role := range roles {
|
||||
s = append(s, role.String())
|
||||
}
|
||||
|
||||
return s
|
||||
}
|
||||
|
||||
func FromStrings(s []string) []Role {
|
||||
var roles []Role
|
||||
for _, e := range s {
|
||||
role, err := fromString(e)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
roles = append(roles, role)
|
||||
}
|
||||
|
||||
return roles
|
||||
}
|
||||
50
roles.go
Normal file
50
roles.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package catalyst
|
||||
|
||||
import maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
var Admin = &maut.Role{
|
||||
Name: "admin",
|
||||
Permissions: append(engineer.Permissions,
|
||||
"backup:create",
|
||||
"backup:restore",
|
||||
"dashboard:write",
|
||||
"job:read",
|
||||
"job:write",
|
||||
"log:read",
|
||||
"settings:write",
|
||||
"ticket:delete",
|
||||
"tickettype:read",
|
||||
"user:write",
|
||||
"userdata:read",
|
||||
"userdata:write",
|
||||
),
|
||||
}
|
||||
|
||||
var engineer = &maut.Role{
|
||||
Name: "engineer",
|
||||
Permissions: append(analyst.Permissions,
|
||||
"automation:write",
|
||||
"playbook:write",
|
||||
"template:write",
|
||||
"tickettype:write",
|
||||
),
|
||||
}
|
||||
|
||||
var analyst = &maut.Role{
|
||||
Name: "analyst",
|
||||
Permissions: []string{
|
||||
"automation:read",
|
||||
"currentuser:read",
|
||||
"currentuserdata:read",
|
||||
"currentuserdata:write",
|
||||
"dashboard:read",
|
||||
"file:read",
|
||||
"file:write",
|
||||
"playbook:read",
|
||||
"settings:read",
|
||||
"template:read",
|
||||
"ticket:read",
|
||||
"ticket:write",
|
||||
"user:read",
|
||||
},
|
||||
}
|
||||
87
server.go
87
server.go
@@ -7,17 +7,14 @@ import (
|
||||
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/auth"
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/busservice"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/hooks"
|
||||
"github.com/SecurityBrewery/catalyst/index"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
"github.com/SecurityBrewery/catalyst/service"
|
||||
"github.com/SecurityBrewery/catalyst/storage"
|
||||
)
|
||||
@@ -27,11 +24,9 @@ type Config struct {
|
||||
DB *database.Config
|
||||
Storage *storage.Config
|
||||
|
||||
Secret []byte
|
||||
Auth *auth.Config
|
||||
Auth *maut.Config
|
||||
ExternalAddress string
|
||||
InternalAddress string
|
||||
InitialAPIKey string
|
||||
Network string
|
||||
Port int
|
||||
}
|
||||
@@ -49,12 +44,6 @@ func New(hooks *hooks.Hooks, config *Config) (*Server, error) {
|
||||
ctx, cancel := context.WithTimeout(ctx, time.Minute*10)
|
||||
defer cancel()
|
||||
|
||||
if config.Auth.OIDCAuthEnable {
|
||||
if err := config.Auth.Load(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
|
||||
catalystStorage, err := storage.New(config.Storage)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -72,29 +61,19 @@ func New(hooks *hooks.Hooks, config *Config) (*Server, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
busservice.New(config.InternalAddress+"/api", config.InitialAPIKey, config.Network, catalystBus, catalystDatabase)
|
||||
busservice.New(config.InternalAddress+"/api", config.Auth.InitialAPIKey, config.Network, catalystBus, catalystDatabase)
|
||||
|
||||
catalystService, err := service.New(catalystBus, catalystDatabase, catalystStorage, GetVersion())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if config.InitialAPIKey != "" {
|
||||
_ = catalystDatabase.UserDelete(ctx, "setup")
|
||||
|
||||
ctx = busdb.UserContext(ctx, &model.UserResponse{
|
||||
ID: "setup",
|
||||
Roles: role.Strings(role.Explode(role.Admin)),
|
||||
Apikey: false,
|
||||
Blocked: false,
|
||||
})
|
||||
_, err = catalystDatabase.UserCreateSetupAPIKey(ctx, config.InitialAPIKey)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
authenticator, err := maut.NewAuthenticator(ctx, config.Auth, newCatalystResolver(catalystDatabase))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
apiServer, err := setupAPI(catalystService, catalystStorage, catalystDatabase, config.DB, catalystBus, config)
|
||||
apiServer, err := setupAPI(authenticator, catalystService, catalystStorage, catalystDatabase, config.DB, catalystBus, config)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -108,32 +87,22 @@ func New(hooks *hooks.Hooks, config *Config) (*Server, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func setupAPI(catalystService *service.Service, catalystStorage *storage.Storage, catalystDatabase *database.Database, dbConfig *database.Config, bus *bus.Bus, config *Config) (chi.Router, error) {
|
||||
secureJar := auth.NewJar(config.Secret)
|
||||
|
||||
func setupAPI(authenticator *maut.Authenticator, catalystService *service.Service, catalystStorage *storage.Storage, catalystDatabase *database.Database, dbConfig *database.Config, bus *bus.Bus, config *Config) (chi.Router, error) {
|
||||
middlewares := []func(next http.Handler) http.Handler{
|
||||
auth.Authenticate(catalystDatabase, config.Auth, secureJar),
|
||||
auth.AuthorizeBlockedUser(),
|
||||
authenticator.Authenticate(),
|
||||
authenticator.AuthorizeBlockedUser(),
|
||||
}
|
||||
|
||||
// create server
|
||||
apiServer := api.NewServer(catalystService, auth.AuthorizeRole, middlewares...)
|
||||
fileReadWrite := auth.AuthorizeRole([]string{role.FileReadWrite.String()})
|
||||
tudHandler := tusdUpload(catalystDatabase, bus, catalystStorage.S3(), config.ExternalAddress)
|
||||
apiServer.With(fileReadWrite).Head("/files/{ticketID}/tusd/{id}", tudHandler)
|
||||
apiServer.With(fileReadWrite).Patch("/files/{ticketID}/tusd/{id}", tudHandler)
|
||||
apiServer.With(fileReadWrite).Post("/files/{ticketID}/tusd", tudHandler)
|
||||
apiServer.With(fileReadWrite).Post("/files/{ticketID}/upload", upload(catalystDatabase, catalystStorage.S3(), catalystStorage.Uploader()))
|
||||
apiServer.With(fileReadWrite).Get("/files/{ticketID}/download/{key}", download(catalystStorage.Downloader()))
|
||||
|
||||
apiServer.With(auth.AuthorizeRole([]string{role.BackupRead.String()})).Get("/backup/create", backupHandler(catalystStorage, dbConfig))
|
||||
apiServer.With(auth.AuthorizeRole([]string{role.BackupRestore.String()})).Post("/backup/restore", restoreHandler(catalystStorage, catalystDatabase, dbConfig))
|
||||
apiServer := api.NewServer(catalystService, permissionAuth(authenticator), middlewares...)
|
||||
apiServer.Mount("/files", fileServer(authenticator, catalystDatabase, bus, catalystStorage, config))
|
||||
apiServer.Mount("/backup", backupServer(authenticator, catalystStorage, catalystDatabase, dbConfig))
|
||||
|
||||
server := chi.NewRouter()
|
||||
server.Use(middleware.RequestID, middleware.RealIP, middleware.Logger, middleware.Recoverer)
|
||||
server.Mount("/api", apiServer)
|
||||
server.Mount("/auth", authenticator.Server())
|
||||
server.With(middlewares...).Handle("/wss", handleWebSocket(bus))
|
||||
server.Mount("/auth", auth.Server(config.Auth, catalystDatabase, secureJar))
|
||||
|
||||
server.Get("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
http.Redirect(w, r, "/ui/", http.StatusFound)
|
||||
@@ -141,3 +110,31 @@ func setupAPI(catalystService *service.Service, catalystStorage *storage.Storage
|
||||
|
||||
return server, nil
|
||||
}
|
||||
|
||||
func permissionAuth(authenticator *maut.Authenticator) func([]string) func(http.Handler) http.Handler {
|
||||
return func(strings []string) func(http.Handler) http.Handler {
|
||||
return authenticator.AuthorizePermission(strings...)
|
||||
}
|
||||
}
|
||||
|
||||
func fileServer(authenticator *maut.Authenticator, catalystDatabase *database.Database, bus *bus.Bus, catalystStorage *storage.Storage, config *Config) *chi.Mux {
|
||||
fileRW := authenticator.AuthorizePermission("file:read", "file:write") // TODO: add test
|
||||
tudHandler := tusdUpload(catalystDatabase, bus, catalystStorage.S3(), config.ExternalAddress)
|
||||
server := chi.NewRouter()
|
||||
server.With(fileRW).Head("/{ticketID}/tusd/{id}", tudHandler)
|
||||
server.With(fileRW).Patch("/{ticketID}/tusd/{id}", tudHandler)
|
||||
server.With(fileRW).Post("/{ticketID}/tusd", tudHandler)
|
||||
server.With(fileRW).Post("/{ticketID}/upload", upload(catalystDatabase, catalystStorage.S3(), catalystStorage.Uploader()))
|
||||
server.With(fileRW).Get("/{ticketID}/download/{key}", download(catalystStorage.Downloader()))
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func backupServer(authenticator *maut.Authenticator, catalystStorage *storage.Storage, catalystDatabase *database.Database, dbConfig *database.Config) *chi.Mux {
|
||||
server := chi.NewRouter()
|
||||
// TODO: add test
|
||||
server.With(authenticator.AuthorizePermission("backup:create")).Get("/create", backupHandler(catalystStorage, dbConfig))
|
||||
server.With(authenticator.AuthorizePermission("backup:restore")).Post("/restore", restoreHandler(catalystStorage, catalystDatabase, dbConfig))
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
@@ -4,10 +4,10 @@ import (
|
||||
"context"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/storage"
|
||||
)
|
||||
|
||||
@@ -28,7 +28,7 @@ func (s *Service) publishRequest(ctx context.Context, err error, function string
|
||||
}
|
||||
if ids != nil {
|
||||
userID := "unknown"
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
user, _, ok := maut.UserFromContext(ctx)
|
||||
if ok {
|
||||
userID = user.ID
|
||||
}
|
||||
|
||||
@@ -3,11 +3,10 @@ package service
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/role"
|
||||
)
|
||||
|
||||
func (s *Service) GetSettings(ctx context.Context) (*model.SettingsResponse, error) {
|
||||
@@ -29,7 +28,7 @@ func (s *Service) SaveSettings(ctx context.Context, settings *model.Settings) (*
|
||||
}
|
||||
|
||||
func (s *Service) settings(ctx context.Context, globalSettings *model.Settings) (*model.SettingsResponse, error) {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
user, permissions, ok := maut.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no user in context")
|
||||
}
|
||||
@@ -47,13 +46,11 @@ func (s *Service) settings(ctx context.Context, globalSettings *model.Settings)
|
||||
if userData.Timeformat != nil {
|
||||
globalSettings.Timeformat = *userData.Timeformat
|
||||
}
|
||||
roles := role.Strings(role.List())
|
||||
sort.Strings(roles)
|
||||
|
||||
return &model.SettingsResponse{
|
||||
Tier: model.SettingsResponseTierCommunity,
|
||||
Version: s.version,
|
||||
Roles: roles,
|
||||
Roles: permissions,
|
||||
TicketTypes: ticketTypeList,
|
||||
ArtifactStates: globalSettings.ArtifactStates,
|
||||
ArtifactKinds: globalSettings.ArtifactKinds,
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
)
|
||||
|
||||
@@ -59,11 +59,16 @@ func (s *Service) DeleteUser(ctx context.Context, s2 string) (err error) {
|
||||
}
|
||||
|
||||
func (s *Service) CurrentUser(ctx context.Context) (*model.UserResponse, error) {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
user, _, ok := maut.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no user in context")
|
||||
}
|
||||
s.publishRequest(ctx, nil, "CurrentUser", userResponseID(user))
|
||||
s.publishRequest(ctx, nil, "CurrentUser", userID(user.ID))
|
||||
|
||||
return user, nil
|
||||
return &model.UserResponse{
|
||||
ID: user.ID,
|
||||
Apikey: user.APIKey,
|
||||
Blocked: user.Blocked,
|
||||
Roles: user.Roles,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -6,9 +6,9 @@ import (
|
||||
"fmt"
|
||||
|
||||
"github.com/arangodb/go-driver"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
)
|
||||
|
||||
@@ -39,7 +39,7 @@ func (s *Service) UpdateUserData(ctx context.Context, id string, data *model.Use
|
||||
}
|
||||
|
||||
func (s *Service) CurrentUserData(ctx context.Context) (doc *model.UserDataResponse, err error) {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
user, _, ok := maut.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no user in context")
|
||||
}
|
||||
@@ -48,7 +48,7 @@ func (s *Service) CurrentUserData(ctx context.Context) (doc *model.UserDataRespo
|
||||
}
|
||||
|
||||
func (s *Service) UpdateCurrentUserData(ctx context.Context, data *model.UserData) (doc *model.UserDataResponse, err error) {
|
||||
user, ok := busdb.UserFromContext(ctx)
|
||||
user, _, ok := maut.UserFromContext(ctx)
|
||||
if !ok {
|
||||
return nil, errors.New("no user in context")
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/migrations"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
@@ -13,7 +15,7 @@ import (
|
||||
var (
|
||||
bobSetting = &model.UserData{Email: pointer.String("bob@example.org"), Name: pointer.String("Bob Bad")}
|
||||
bobForm = &model.UserForm{ID: "bob", Blocked: false, Roles: []string{"admin"}}
|
||||
Bob = &model.UserResponse{ID: "bob", Blocked: false, Roles: []string{"admin"}}
|
||||
Bob = &maut.User{ID: "bob", Blocked: false, Roles: []string{"admin"}}
|
||||
)
|
||||
|
||||
func SetupTestData(ctx context.Context, db *database.Database) error {
|
||||
|
||||
21
test/test.go
21
test/test.go
@@ -12,13 +12,12 @@ import (
|
||||
"github.com/arangodb/go-driver"
|
||||
"github.com/coreos/go-oidc/v3/oidc"
|
||||
"github.com/go-chi/chi/v5"
|
||||
maut "github.com/jonas-plum/maut/auth"
|
||||
"golang.org/x/oauth2"
|
||||
|
||||
"github.com/SecurityBrewery/catalyst"
|
||||
"github.com/SecurityBrewery/catalyst/auth"
|
||||
"github.com/SecurityBrewery/catalyst/bus"
|
||||
"github.com/SecurityBrewery/catalyst/database"
|
||||
"github.com/SecurityBrewery/catalyst/database/busdb"
|
||||
"github.com/SecurityBrewery/catalyst/generated/api"
|
||||
"github.com/SecurityBrewery/catalyst/generated/model"
|
||||
"github.com/SecurityBrewery/catalyst/hooks"
|
||||
@@ -28,14 +27,13 @@ import (
|
||||
)
|
||||
|
||||
func Context() context.Context {
|
||||
return busdb.UserContext(context.Background(), Bob)
|
||||
return maut.UserContext(context.Background(), Bob, nil) // TODO add permissions ?
|
||||
}
|
||||
|
||||
func Config(ctx context.Context) (*catalyst.Config, error) {
|
||||
config := &catalyst.Config{
|
||||
InitialAPIKey: "test",
|
||||
IndexPath: "index.bleve",
|
||||
Network: "catalyst",
|
||||
IndexPath: "index.bleve",
|
||||
Network: "catalyst",
|
||||
DB: &database.Config{
|
||||
Host: "http://localhost:8529",
|
||||
User: "root",
|
||||
@@ -46,8 +44,9 @@ func Config(ctx context.Context) (*catalyst.Config, error) {
|
||||
User: "minio",
|
||||
Password: "minio123",
|
||||
},
|
||||
Secret: []byte("4ef5b29539b70233dd40c02a1799d25079595565e05a193b09da2c3e60ada1cd"),
|
||||
Auth: &auth.Config{
|
||||
Auth: &maut.Config{
|
||||
InitialAPIKey: "test",
|
||||
CookieSecret: []byte("4ef5b29539b70233dd40c02a1799d25079595565e05a193b09da2c3e60ada1cd"),
|
||||
SimpleAuthEnable: true,
|
||||
APIKeyAuthEnable: true,
|
||||
OIDCAuthEnable: true,
|
||||
@@ -66,10 +65,6 @@ func Config(ctx context.Context) (*catalyst.Config, error) {
|
||||
},
|
||||
}
|
||||
|
||||
if err := config.Auth.Load(ctx); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return config, nil
|
||||
}
|
||||
|
||||
@@ -176,7 +171,7 @@ func Server(t *testing.T) (context.Context, *catalyst.Config, *bus.Bus, *index.I
|
||||
catalystServer := api.NewServer(catalystService, func(s []string) func(http.Handler) http.Handler {
|
||||
return func(handler http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
handler.ServeHTTP(w, busdb.SetContext(r, Bob))
|
||||
handler.ServeHTTP(w, r.WithContext(maut.UserContext(r.Context(), Bob, nil)))
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -3,7 +3,7 @@ beforeEach(() => {
|
||||
|
||||
cy.login();
|
||||
|
||||
cy.getCookie('user').should('exist');
|
||||
cy.getCookie('maut_user').should('exist');
|
||||
|
||||
cy.intercept('GET', '/api/userdata/demo', { fixture: 'userdata_demo.json' })
|
||||
cy.intercept('GET', '/api/users/demo', { fixture: 'user_demo.json' })
|
||||
|
||||
@@ -2,38 +2,5 @@
|
||||
"apikey": false,
|
||||
"blocked": false,
|
||||
"id": "demo",
|
||||
"roles": [
|
||||
"admin:backup:read",
|
||||
"admin:backup:restore",
|
||||
"admin:dashboard:write",
|
||||
"admin:group:write",
|
||||
"admin:job:read",
|
||||
"admin:job:write",
|
||||
"admin:log:read",
|
||||
"admin:settings:write",
|
||||
"admin:ticket:delete",
|
||||
"admin:user:write",
|
||||
"admin:userdata:read",
|
||||
"admin:userdata:write",
|
||||
"analyst:automation:read",
|
||||
"analyst:currentsettings:write",
|
||||
"analyst:currentuser:read",
|
||||
"analyst:currentuserdata:read",
|
||||
"analyst:dashboard:read",
|
||||
"analyst:file",
|
||||
"analyst:group:read",
|
||||
"analyst:playbook:read",
|
||||
"analyst:rule:read",
|
||||
"analyst:settings:read",
|
||||
"analyst:template:read",
|
||||
"analyst:ticket:read",
|
||||
"analyst:ticket:write",
|
||||
"analyst:tickettype:read",
|
||||
"analyst:user:read",
|
||||
"engineer:automation:write",
|
||||
"engineer:playbook:write",
|
||||
"engineer:rule:write",
|
||||
"engineer:template:write",
|
||||
"engineer:tickettype:write"
|
||||
]
|
||||
"roles": [ "admin" ]
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
<v-form ref="form" v-model="valid" @submit.prevent="login">
|
||||
<v-card class="pa-4">
|
||||
<div class="d-flex justify-center">
|
||||
<v-img src="/ui/flask.svg" height="100" width="100" class="flex-grow-0"></v-img>
|
||||
<v-img src="/ui/static/flask.svg" height="100" width="100" class="flex-grow-0"></v-img>
|
||||
</div>
|
||||
<v-card-title class="text-center justify-center">
|
||||
Catalyst Login
|
||||
@@ -45,7 +45,7 @@
|
||||
<v-list>
|
||||
<v-list-item class="px-2" :to="{ name: 'Home' }">
|
||||
<v-list-item-avatar rounded="0">
|
||||
<v-img src="/ui/flask_white.svg" :width="40"></v-img>
|
||||
<v-img src="/ui/static/flask_white.svg" :width="40"></v-img>
|
||||
</v-list-item-avatar>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="title">
|
||||
@@ -208,16 +208,16 @@ export default Vue.extend({
|
||||
valid: true,
|
||||
authenticated: false,
|
||||
settings: [
|
||||
{ icon: "mdi-format-list-bulleted-type", name: "Ticket Types", to: "TicketTypeList", role: "engineer:tickettype:write" },
|
||||
{ icon: "mdi-file-hidden", name: "Templates", to: "TemplateList", role: "analyst:template:read" },
|
||||
{ icon: "mdi-file-cog-outline", name: "Playbooks", to: "PlaybookList", role: "analyst:playbook:read" },
|
||||
{ icon: "mdi-flash", name: "Automations", to: "AutomationList", role: "analyst:automation:read" },
|
||||
{ icon: "mdi-filter", name: "Ingestion Rules", to: "RuleList", role: "analyst:rule:read", tier: "enterprise" },
|
||||
{ icon: "mdi-account", name: "Users & API Keys", to: "UserList", role: "admin:user:write" },
|
||||
{ icon: "mdi-account-group", name: "Groups", to: "GroupList", role: "admin:group:write", tier: "enterprise" },
|
||||
{ icon: "mdi-cogs", name: "User Data", to: "UserDataList", role: "admin:userdata:write" },
|
||||
{ icon: "mdi-format-list-checks", name: "Jobs", to: "JobList", role: "admin:job:write" },
|
||||
{ icon: "mdi-cog", name: "Settings", to: "Settings", role: "admin:settings:write" },
|
||||
{ icon: "mdi-format-list-bulleted-type", name: "Ticket Types", to: "TicketTypeList", role: "tickettype:write" },
|
||||
{ icon: "mdi-file-hidden", name: "Templates", to: "TemplateList", role: "template:read" },
|
||||
{ icon: "mdi-file-cog-outline", name: "Playbooks", to: "PlaybookList", role: "playbook:read" },
|
||||
{ icon: "mdi-flash", name: "Automations", to: "AutomationList", role: "automation:read" },
|
||||
{ icon: "mdi-filter", name: "Ingestion Rules", to: "RuleList", role: "rule:read", tier: "enterprise" },
|
||||
{ icon: "mdi-account", name: "Users & API Keys", to: "UserList", role: "user:write" },
|
||||
{ icon: "mdi-account-group", name: "Groups", to: "GroupList", role: "group:write", tier: "enterprise" },
|
||||
{ icon: "mdi-cogs", name: "User Data", to: "UserDataList", role: "userdata:write" },
|
||||
{ icon: "mdi-format-list-checks", name: "Jobs", to: "JobList", role: "job:write" },
|
||||
{ icon: "mdi-cog", name: "Settings", to: "Settings", role: "settings:write" },
|
||||
],
|
||||
mini: true,
|
||||
goto: "",
|
||||
@@ -235,7 +235,7 @@ export default Vue.extend({
|
||||
},
|
||||
internal: function (): Array<any> {
|
||||
return [
|
||||
{ icon: "mdi-view-dashboard", name: "Dashboards", to: "DashboardList", role: "analyst:dashboard:read" },
|
||||
{ icon: "mdi-view-dashboard", name: "Dashboards", to: "DashboardList", role: "dashboard:read" },
|
||||
{ icon: "mdi-check-bold", name: "Open Tasks", to: "TaskList", count: this.$store.state.task_count },
|
||||
]
|
||||
},
|
||||
@@ -280,8 +280,8 @@ export default Vue.extend({
|
||||
this.$router.push({ name: "TicketList", params: { type: type } });
|
||||
},
|
||||
hasRole: function (s: string) {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -151,8 +151,8 @@ export default Vue.extend({
|
||||
return DateTime.fromISO(s).toFormat(format);
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -41,8 +41,8 @@ export default Vue.extend({
|
||||
return true;
|
||||
}
|
||||
let has = false;
|
||||
if (this.$store.state.user.roles) {
|
||||
this.lodash.forEach(this.$store.state.user.roles, (userRole) => {
|
||||
if (this.$store.state.settings.roles) {
|
||||
this.lodash.forEach(this.$store.state.settings.roles, (userRole) => {
|
||||
if (link.role === userRole || this.lodash.startsWith(link.role, userRole + ":")) {
|
||||
has = true;
|
||||
}
|
||||
|
||||
@@ -119,8 +119,8 @@ export default Vue.extend({
|
||||
this.dialog = false;
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -72,7 +72,7 @@ export default Vue.extend({
|
||||
},
|
||||
computed: {
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("engineer:automation:write");
|
||||
return !this.hasRole("automation:write");
|
||||
},
|
||||
types: function (): Array<string> {
|
||||
return [ AutomationResponseTypeEnum.Global, AutomationResponseTypeEnum.Playbook, AutomationResponseTypeEnum.Artifact ]
|
||||
@@ -104,8 +104,8 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
itemname="id"
|
||||
singular="Automation"
|
||||
plural="Automations"
|
||||
writepermission="engineer:automation:write"
|
||||
writepermission="automation:write"
|
||||
@delete="deleteAutomation"
|
||||
></List>
|
||||
</v-main>
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
itemname="name"
|
||||
singular="Dashboard"
|
||||
plural="Dashboards"
|
||||
writepermission="admin:dashboard:write"
|
||||
writepermission="dashboard:write"
|
||||
@delete="deleteDashboard"
|
||||
></List>
|
||||
</v-main>
|
||||
|
||||
@@ -94,7 +94,7 @@ export default Vue.extend({
|
||||
},
|
||||
computed: {
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("admin:job:write");
|
||||
return !this.hasRole("job:write");
|
||||
},
|
||||
globalautomations: function (): Array<AutomationResponse> {
|
||||
if (!this.automations) {
|
||||
@@ -157,8 +157,8 @@ export default Vue.extend({
|
||||
});
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export default Vue.extend({
|
||||
}),
|
||||
computed: {
|
||||
canWrite: function (): boolean {
|
||||
return this.hasRole("admin:job:write");
|
||||
return this.hasRole("job:write");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -80,8 +80,8 @@ export default Vue.extend({
|
||||
});
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -174,7 +174,7 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("engineer:playbook:write");
|
||||
return !this.hasRole("playbook:write");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -286,8 +286,8 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
singular="Playbook"
|
||||
plural="Playbooks"
|
||||
@delete="deletePlaybook"
|
||||
writepermission="engineer:playbook:write"
|
||||
writepermission="playbook:write"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
@@ -47,7 +47,7 @@ export default Vue.extend({
|
||||
},
|
||||
computed: {
|
||||
readonly: function (): boolean {
|
||||
return !this.hasRole("engineer:template:write");
|
||||
return !this.hasRole("template:write");
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
@@ -81,8 +81,8 @@ export default Vue.extend({
|
||||
}
|
||||
},
|
||||
hasRole: function (s: string): boolean {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
itemname="name"
|
||||
singular="Template"
|
||||
plural="Templates"
|
||||
writepermission="engineer:template:write"
|
||||
writepermission="template:write"
|
||||
@delete="deleteTemplate"
|
||||
></List>
|
||||
</v-main>
|
||||
|
||||
@@ -761,7 +761,7 @@
|
||||
<div style="display: flex; align-items: center" class="pb-1">
|
||||
<span class="text--disabled">Files</span>
|
||||
<v-spacer></v-spacer>
|
||||
<v-btn v-if="hasRole('analyst:file')" small icon @click="fileDialog = true">
|
||||
<v-btn v-if="hasRole('file')" small icon @click="fileDialog = true">
|
||||
<v-icon>mdi-plus</v-icon>
|
||||
</v-btn>
|
||||
</div>
|
||||
@@ -1017,8 +1017,8 @@ export default Vue.extend({
|
||||
},
|
||||
methods: {
|
||||
hasRole: function (s: string) {
|
||||
if (this.$store.state.user.roles) {
|
||||
return this.lodash.includes(this.$store.state.user.roles, s);
|
||||
if (this.$store.state.settings.roles) {
|
||||
return this.lodash.includes(this.$store.state.settings.roles, s);
|
||||
}
|
||||
return false;
|
||||
},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
singular="Ticket Type"
|
||||
plural="Ticket Types"
|
||||
@delete="deleteTicketType"
|
||||
writepermission="engineer:tickettype:write"
|
||||
writepermission="tickettype:write"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
plural="User Data"
|
||||
:show-new="false"
|
||||
:deletable="false"
|
||||
writepermission="admin:userdata:write"
|
||||
writepermission="userdata:write"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
singular="User / API Key"
|
||||
plural="Users / API Keys"
|
||||
@delete="deleteUser"
|
||||
writepermission="admin:user:write"
|
||||
writepermission="user:write"
|
||||
></List>
|
||||
</v-main>
|
||||
</template>
|
||||
|
||||
Reference in New Issue
Block a user