Skip to content

Commit

Permalink
add default group for authenticated sessions
Browse files Browse the repository at this point in the history
  • Loading branch information
jlarfors committed Nov 17, 2024
1 parent 0499d98 commit 3eb7ed7
Showing 10 changed files with 125 additions and 59 deletions.
2 changes: 1 addition & 1 deletion pkg/auth/role.go
Original file line number Diff line number Diff line change
@@ -29,7 +29,7 @@ type RoleSpec struct {

type Rule struct {
// Name of a resource that this rule targets.
Name *string `json:"name,omitempty" cue:""`
Name *string `json:"name,omitempty"`
// Kind of a resource that this rule targets.
Kind *string `json:"kind,omitempty" cue:""`
// Group of a resource that this rule targets.
8 changes: 8 additions & 0 deletions pkg/auth/rolebinding.go
Original file line number Diff line number Diff line change
@@ -44,3 +44,11 @@ type Subject struct {
// Name is the name of the subject.
Name string `json:"name" cue:""`
}

func RoleRefFromRole(role Role) RoleRef {
return RoleRef{
Group: role.ObjectGroup(),
Kind: role.ObjectKind(),
Name: role.ObjectMeta.Name,
}
}
8 changes: 8 additions & 0 deletions pkg/auth/sessions.go
Original file line number Diff line number Diff line change
@@ -17,6 +17,12 @@ const (
bucketSession = "hz_session"
)

const (
// GroupSystemAuthenticated is a group all users with a session belong to.
// It is a way of identifying "anyone who is authenticated".
GroupSystemAuthenticated = "system:authenticated"
)

var (
ErrAuthenticationMissing = &hz.Error{
Status: http.StatusBadRequest,
@@ -96,6 +102,8 @@ func (s *Sessions) Get(ctx context.Context, session string) (UserInfo, error) {
Message: "unmarshal user: " + err.Error(),
}
}
// Add default groups.
user.Groups = append(user.Groups, GroupSystemAuthenticated)
return user, nil
}

2 changes: 2 additions & 0 deletions pkg/auth/sessions_test.go
Original file line number Diff line number Diff line change
@@ -44,6 +44,8 @@ func TestSessions(t *testing.T) {

userInfo, err := sessions.Get(ctx, sessionID)
tu.AssertNoError(t, err)
// Add default groups to claims, as expected.
claims.Groups = append(claims.Groups, GroupSystemAuthenticated)
tu.AssertEqual(t, claims, userInfo)

err = sessions.Delete(ctx, sessionID)
7 changes: 5 additions & 2 deletions pkg/gateway/handler.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package gateway

import (
"fmt"
"net/http"

"github.com/nats-io/nats.go"
@@ -67,7 +68,8 @@ func (d *DefaultHandler) PostNamespaces(
) {
name := r.FormValue("namespace-name")
if name == "" {
http.Error(w, "namespace name is required", http.StatusBadRequest)
_ = namespacesNewForm(name, fmt.Errorf("namespace name is required")).
Render(r.Context(), w)
return
}
client := hz.NewClient(d.Conn, hz.WithClientSessionFromRequest(r))
@@ -80,7 +82,8 @@ func (d *DefaultHandler) PostNamespaces(
}
_, err := nsClient.Apply(r.Context(), ns, hz.WithApplyCreateOnly(true))
if err != nil {
httpError(w, err)
_ = namespacesNewForm(name, err).
Render(r.Context(), w)
return
}
w.Header().Add("HX-Redirect", "/namespaces/"+name)
17 changes: 13 additions & 4 deletions pkg/gateway/namespaces.templ
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
package gateway

import (
"github.com/verifa/horizon/pkg/extensions/core"
)
import "github.com/verifa/horizon/pkg/extensions/core"

templ home() {
<div class="prose prose-a:no-underline mx-auto max-w-7xl px-8 py-8">
@@ -37,6 +35,17 @@ templ namespacePage() {
templ namespacesNewPage() {
<div class="prose prose-a:no-underline mx-auto max-w-7xl px-8 py-8">
<h1>New Namespace</h1>
<form hx-post="/namespaces"><label class="label"><span class="label-text">Name</span></label><input type="text" placeholder="e.g. team-123" id="namespace-name" name="namespace-name" class="input input-bordered w-full max-w-xs"/><button type="submit" class="btn">Submit</button></form>
@namespacesNewForm("", nil)
</div>
}

templ namespacesNewForm(name string, err error) {
<form hx-post="/namespaces" hx-swap="outerHTML">
<label class="label"><span class="label-text">Name</span></label>
<input type="text" placeholder="e.g. team-123" id="namespace-name" name="namespace-name" class="input input-bordered w-full max-w-xs" value={ name }/>
<button type="submit" class="btn">Submit</button>
if err != nil {
<p class="text-error">{ "Error: "+ err.Error() }</p>
}
</form>
}
78 changes: 73 additions & 5 deletions pkg/gateway/namespaces_templ.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 15 additions & 40 deletions pkg/gateway/server.go
Original file line number Diff line number Diff line change
@@ -61,12 +61,6 @@ func WithDummyAuthUsers(users ...storage.User) ServerOption {
}
}

func WithDummyAuthDefault(b bool) ServerOption {
return func(o *serverOptions) {
o.dummyAuthDefault = b
}
}

func WithPort(port int) ServerOption {
return func(o *serverOptions) {
o.port = port
@@ -79,8 +73,7 @@ type serverOptions struct {
Conn *nats.Conn
oidc *OIDCConfig

dummyAuthUsers map[string]*storage.User
dummyAuthDefault bool
dummyAuthUsers map[string]*storage.User

listener net.Listener
port int
@@ -164,32 +157,24 @@ func (s *Server) start(
)
r.Use(middleware.Recoverer)

if !validateOneTrue(
opt.oidc != nil,
opt.dummyAuthUsers != nil,
opt.dummyAuthDefault,
) {
opt.dummyAuthDefault = true
}
//
// Auth
//
if opt.oidc == nil {
if opt.dummyAuthDefault {
opt.dummyAuthUsers = map[string]*storage.User{
"admin": {
ID: "admin",
Username: "admin",
Password: "admin",
Groups: []string{"admin"},
FirstName: "Admin",
LastName: "Admin",
Email: "admin@localhost",
EmailVerified: true,
// How posh of you, admin!
PreferredLanguage: language.BritishEnglish,
},
}
if opt.dummyAuthUsers == nil {
opt.dummyAuthUsers = make(map[string]*storage.User)
}
opt.dummyAuthUsers["admin"] = &storage.User{
ID: "admin",
Username: "admin",
Password: "admin",
Groups: []string{"admin"},
FirstName: "Admin",
LastName: "Admin",
Email: "admin@localhost",
EmailVerified: true,
// How posh of you, admin!
PreferredLanguage: language.BritishEnglish,
}
// Configure the dummyoidc server.
dummyServer, err := dummyoidc.Start(ctx, dummyoidc.Config{
@@ -357,16 +342,6 @@ func (s *Server) serveLoggedOut(w http.ResponseWriter, r *http.Request) {
layout("Logged Out", nil, body).Render(r.Context(), w)
}

func validateOneTrue(b ...bool) bool {
var count int
for _, v := range b {
if v {
count++
}
}
return count == 1
}

func httpError(w http.ResponseWriter, err error) {
var hzErr *hz.Error
if errors.As(err, &hzErr) {
6 changes: 0 additions & 6 deletions pkg/server/server.go
Original file line number Diff line number Diff line change
@@ -212,12 +212,6 @@ func (s *Server) Start(ctx context.Context, opts ...ServerOption) error {
s.Broker = &broker
}
if opt.runGateway {
defaultOptions := []gateway.ServerOption{
gateway.WithDummyAuthDefault(true),
}
if opt.gatewayOptions == nil {
opt.gatewayOptions = defaultOptions
}
gw, err := gateway.Start(ctx, s.Conn, s.Auth, opt.gatewayOptions...)
if err != nil {
return fmt.Errorf("starting gateway: %w", err)
1 change: 0 additions & 1 deletion pkg/server/test.go
Original file line number Diff line number Diff line change
@@ -30,7 +30,6 @@ func Test(t *testing.T, ctx context.Context, opts ...ServerOption) *Server {
),
WithGatewayOptions(
gateway.WithPort(gwPort),
gateway.WithDummyAuthDefault(true),
),
WithAuthOptions(auth.WithAdminGroups("admin")),
)

0 comments on commit 3eb7ed7

Please sign in to comment.