Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/new-ui/v1beta1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ func main() {
http.HandleFunc("/katib/", kuh.ServeIndex(*buildDir))
http.Handle("/katib/static/", http.StripPrefix("/katib/", frontend))

http.HandleFunc("/katib/fetch_experiments/", kuh.FetchAllExperiments)
http.HandleFunc("/katib/fetch_experiments/", kuh.FetchExperiments)

http.HandleFunc("/katib/create_experiment/", kuh.CreateExperiment)

Expand Down
15 changes: 15 additions & 0 deletions pkg/controller.v1beta1/consts/const.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,23 @@ import (

const (

// ActionTypeCreate is the create CRUD action
ActionTypeCreate = "create"
// ActionTypeList is the list CRUD action
ActionTypeList = "list"
// ActionTypeGet is the get CRUD action
ActionTypeGet = "get"
// ActionTypeUpdate is the update CRUD action
ActionTypeUpdate = "update"
// ActionTypeDelete is the delete CRUD action
ActionTypeDelete = "delete"

// PluralTrial is the plural for Trial object
PluralTrial = "trials"
// PluralExperiment is the plural for Experiment object
PluralExperiment = "experiments"
// PluralSuggestion is the plural for Suggestion object
PluralSuggestion = "suggestions"

// ConfigExperimentSuggestionName is the config name of the
// suggestion client implementation in experiment controller.
Expand Down
1 change: 1 addition & 0 deletions pkg/new-ui/v1beta1/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ This is the recommended way to test the web app e2e. In order to build the UI an
For example, if you use port-forwarding to expose `katib-db-manager`, run this command:

```
export APP_DISABLE_AUTH=true
go run main.go --build-dir=../../../pkg/new-ui/v1beta1/frontend/dist --port=8080 --db-manager-address=localhost:6789
```

Expand Down
95 changes: 95 additions & 0 deletions pkg/new-ui/v1beta1/authzn.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
package v1beta1

import (
"context"
"errors"
"fmt"
"log"
"net/http"
"strings"

"github.com/kubeflow/katib/pkg/util/v1beta1/env"
v1 "k8s.io/api/authorization/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"sigs.k8s.io/controller-runtime/pkg/client"
)

// ENV variables
var (
USER_HEADER = env.GetEnvOrDefault("USERID_HEADER", "kubeflow-userid")
USER_PREFIX = env.GetEnvOrDefault("USERID_PREFIX", ":")
DISABLE_AUTH = env.GetEnvOrDefault("APP_DISABLE_AUTH", "true")
)

// Function for constructing SubjectAccessReviews (SAR) objects
func CreateSAR(user, verb, namespace, resource, subresource, name string, schema schema.GroupVersion) *v1.SubjectAccessReview {

sar := &v1.SubjectAccessReview{
Spec: v1.SubjectAccessReviewSpec{
User: user,
ResourceAttributes: &v1.ResourceAttributes{
Namespace: namespace,
Verb: verb,
Group: schema.Group,
Version: schema.Version,
Resource: resource,
Subresource: subresource,
Name: name,
},
},
}
return sar
}

func IsAuthorized(verb, namespace, resource, subresource, name string, schema schema.GroupVersion, client client.Client, r *http.Request) (string, error) {

// We disable authn/authz checks when in standalone mode.
if DISABLE_AUTH == "true" {
log.Printf("APP_DISABLE_AUTH set to True. Skipping authentication/authorization checks")
return "", nil
}
// Check if an incoming request is from an authenticated user (kubeflow mode: kubeflow-userid header)
if r.Header.Get(USER_HEADER) == "" {
return "", errors.New("user header not present")
}
user := r.Header.Get(USER_HEADER)
user = strings.Replace(user, USER_PREFIX, "", 1)

// Check if the user is authorized to perform a given action on katib/k8s resources.
sar := CreateSAR(user, verb, namespace, resource, subresource, name, schema)
err := client.Create(context.TODO(), sar)
if err != nil {
log.Printf("Error submitting SubjectAccessReview: %v, %s", sar, err.Error())
return user, err
}

if sar.Status.Allowed {
return user, nil
}

msg := generateUnauthorizedMessage(user, verb, namespace, resource, subresource, schema, sar)
return user, errors.New(msg)
}

func generateUnauthorizedMessage(user, verb, namespace, resource, subresource string, schema schema.GroupVersion, sar *v1.SubjectAccessReview) string {

msg := fmt.Sprintf("User: %s is not authorized to %s", user, verb)

if schema.Group == "" {
msg += fmt.Sprintf(" %s/%s", schema.Version, resource)
} else {
msg += fmt.Sprintf(" %s/%s/%s", schema.Group, schema.Version, resource)
}

if subresource != "" {
msg += fmt.Sprintf("/%s", subresource)
}

if namespace != "" {
msg += fmt.Sprintf(" in namespace: %s", namespace)
}
if sar.Status.Reason != "" {
msg += fmt.Sprintf(" ,reason: %s", sar.Status.Reason)
}
return msg
}
Loading