Skip to content

Commit c150113

Browse files
authored
Merge pull request #46 from thand-io/update-auth-revoke-api
Updated APIs for auth/revoke calls to let users store identity state
2 parents 2123007 + 8fb8af0 commit c150113

22 files changed

Lines changed: 248 additions & 223 deletions

File tree

go.mod

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ require (
2525
github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.36.3
2626
github.com/aws/aws-sdk-go-v2/service/sts v1.38.7
2727
github.com/aws/smithy-go v1.23.1
28-
github.com/blevesearch/bleve/v2 v2.5.3
28+
github.com/blevesearch/bleve/v2 v2.5.4
2929
github.com/charmbracelet/huh v0.8.0
3030
github.com/charmbracelet/lipgloss v1.1.0
3131
github.com/cloudevents/sdk-go/v2 v2.16.2
@@ -62,7 +62,7 @@ require (
6262
golang.org/x/oauth2 v0.32.0
6363
google.golang.org/api v0.252.0
6464
google.golang.org/genai v1.31.0
65-
google.golang.org/genproto v0.0.0-20251014184007-4626949a642f
65+
google.golang.org/genproto v0.0.0-20251020155222-88f65dc88635
6666
google.golang.org/grpc v1.76.0
6767
google.golang.org/protobuf v1.36.10
6868
gopkg.in/gomail.v2 v2.0.0-20160411212932-81ebce5c23df
@@ -125,7 +125,7 @@ require (
125125
github.com/charmbracelet/colorprofile v0.3.2 // indirect
126126
github.com/charmbracelet/x/ansi v0.10.2 // indirect
127127
github.com/charmbracelet/x/cellbuf v0.0.13 // indirect
128-
github.com/charmbracelet/x/exp/strings v0.0.0-20251016201629-54e687c87a08 // indirect
128+
github.com/charmbracelet/x/exp/strings v0.0.0-20251020175859-5c94a71567d3 // indirect
129129
github.com/charmbracelet/x/term v0.2.1 // indirect
130130
github.com/clipperhouse/uax29/v2 v2.2.0 // indirect
131131
github.com/cloudwego/base64x v0.1.6 // indirect
@@ -162,7 +162,6 @@ require (
162162
github.com/golang-jwt/jwt/v4 v4.5.2 // indirect
163163
github.com/golang-jwt/jwt/v5 v5.3.0 // indirect
164164
github.com/golang/mock v1.6.0 // indirect
165-
github.com/golang/protobuf v1.5.4 // indirect
166165
github.com/golang/snappy v1.0.0 // indirect
167166
github.com/google/go-cmp v0.7.0 // indirect
168167
github.com/google/go-querystring v1.1.0 // indirect
@@ -292,7 +291,7 @@ require (
292291
golang.org/x/text v0.30.0 // indirect
293292
golang.org/x/time v0.14.0 // indirect
294293
golang.org/x/tools v0.38.0 // indirect
295-
google.golang.org/genproto/googleapis/api v0.0.0-20251014184007-4626949a642f // indirect
296-
google.golang.org/genproto/googleapis/rpc v0.0.0-20251014184007-4626949a642f // indirect
294+
google.golang.org/genproto/googleapis/api v0.0.0-20251020155222-88f65dc88635 // indirect
295+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251020155222-88f65dc88635 // indirect
297296
gopkg.in/alexcesaro/quotedprintable.v3 v3.0.0-20150716171945-2caba252f4dc // indirect
298297
)

go.sum

Lines changed: 11 additions & 80 deletions
Large diffs are not rendered by default.

internal/daemon/static/elevate_static.html

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ <h1>Static Elevation Request</h1>
1010

1111
<form action="{{.Config.GetApiBasePath}}/elevate" method="GET" class="mt-2 text-left">
1212

13-
<div class="form-section" style="max-width: 600px;">
13+
<div class="form-section" style="max-width: 600px; margin: 0 auto;">
1414
<h3>Select Identities to Assign Role</h3>
1515
<div class="choice-wrapper">
1616
<select name="identities" id="identities" multiple>

internal/models/provider.go

Lines changed: 27 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -141,31 +141,44 @@ type AuthorizeSessionResponse struct {
141141
Url string `json:"url"`
142142
}
143143

144-
type AuthorizeRoleRequest struct {
144+
type RoleRequest struct {
145145
User *User `json:"user"`
146146
Role *Role `json:"role"`
147147
Duration *time.Duration `json:"duration,omitempty"` // Optional duration for temporary access
148148
}
149149

150150
// IsValid checks if any of the fields are nil
151151
// if they are then it returns false
152-
func (r *AuthorizeRoleRequest) IsValid() bool {
153-
return r.User != nil && r.Role != nil && r.Duration != nil
152+
func (r *RoleRequest) IsValid() bool {
153+
return r.User != nil && r.Role != nil
154154
}
155155

156-
func (r *AuthorizeRoleRequest) GetUser() *User {
156+
func (r *RoleRequest) GetUser() *User {
157157
return r.User
158158
}
159159

160-
func (r *AuthorizeRoleRequest) GetRole() *Role {
160+
func (r *RoleRequest) GetRole() *Role {
161161
return r.Role
162162
}
163163

164-
func (r *AuthorizeRoleRequest) GetDuration() *time.Duration {
164+
func (r *RoleRequest) GetDuration() *time.Duration {
165165
return r.Duration
166166
}
167167

168+
type AuthorizeRoleRequest struct {
169+
*RoleRequest
170+
}
171+
168172
type AuthorizeRoleResponse struct {
173+
Metadata map[string]any `json:"metadata,omitempty"` // Any metadata returned from the provider
174+
}
175+
176+
type RevokeRoleRequest struct {
177+
*RoleRequest
178+
AuthorizeRoleResponse *AuthorizeRoleResponse `json:"response,omitempty"`
179+
}
180+
181+
type RevokeRoleResponse struct {
169182
}
170183

171184
type ProviderAuthorizor interface {
@@ -197,15 +210,13 @@ type ProviderRoleBasedAccessControl interface {
197210
ctx context.Context,
198211
req *AuthorizeRoleRequest,
199212
) (
200-
map[string]any, // Return any custom metadata the provider wants to store
213+
*AuthorizeRoleResponse, // Return any custom metadata the provider wants to store
201214
error,
202215
)
203216
RevokeRole(
204217
ctx context.Context,
205-
user *User,
206-
role *Role,
207-
metadata map[string]any, // Any metadata returned from AuthorizeRole
208-
) (map[string]any, error)
218+
req *RevokeRoleRequest, // Any metadata returned from AuthorizeRole
219+
) (*RevokeRoleResponse, error)
209220
}
210221

211222
type BaseProvider struct {
@@ -340,12 +351,15 @@ func (p *BaseProvider) ListResources(ctx context.Context, filters ...string) ([]
340351
func (p *BaseProvider) AuthorizeRole(
341352
ctx context.Context,
342353
req *AuthorizeRoleRequest,
343-
) (map[string]any, error) {
354+
) (*AuthorizeRoleResponse, error) {
344355
// Default implementation does nothing
345356
return nil, fmt.Errorf("the provider '%s' does not implement AuthorizeRole", p.GetProvider())
346357
}
347358

348-
func (p *BaseProvider) RevokeRole(ctx context.Context, user *User, role *Role, metadata map[string]any) (map[string]any, error) {
359+
func (p *BaseProvider) RevokeRole(
360+
ctx context.Context,
361+
req *RevokeRoleRequest,
362+
) (*RevokeRoleResponse, error) {
349363
// Default implementation does nothing
350364
return nil, fmt.Errorf("the provider '%s' does not implement RevokeRole", p.GetProvider())
351365
}

internal/models/user.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,17 @@ func (u *User) GetName() string {
2626
return "Unknown"
2727
}
2828

29+
func (u *User) GetIdentity() string {
30+
if len(u.Email) > 0 {
31+
return u.Email
32+
} else if len(u.Username) > 0 {
33+
return u.Username
34+
} else if len(u.ID) > 0 {
35+
return u.ID
36+
}
37+
return common.ConvertToSnakeCase(u.Name)
38+
}
39+
2940
func (u *User) AsMap() map[string]any {
3041
// Convert User struct to a map[string]any
3142
var mapUser map[string]any

internal/providers/README.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,10 @@ func (p *exampleProvider) AuthorizeRole(ctx context.Context, user *models.User,
5555
}
5656

5757
// Revoke removes access for a user from a role
58-
func (p *exampleProvider) RevokeRole(ctx context.Context, user *models.User, role *models.Role, metadata map[string]any) (map[string]any, error) {
58+
func (p *exampleProvider) RevokeRole(
59+
ctx context.Context,
60+
req *models.RevokeRoleRequest,
61+
) (*models.RevokeRoleResponse, error) {
5962
// TODO: Implement Example revocation logic
6063
return nil, nil
6164
}

internal/providers/aws/rbac.go

Lines changed: 8 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
func (p *awsProvider) AuthorizeRole(
1212
ctx context.Context,
1313
req *models.AuthorizeRoleRequest,
14-
) (map[string]any, error) {
14+
) (*models.AuthorizeRoleResponse, error) {
1515

1616
// Check for nil inputs
1717
if !req.IsValid() {
@@ -32,18 +32,16 @@ func (p *awsProvider) AuthorizeRole(
3232
// Revoke removes access for a user from a role
3333
func (p *awsProvider) RevokeRole(
3434
ctx context.Context,
35-
user *models.User,
36-
role *models.Role,
37-
metadata map[string]any,
38-
) (map[string]any, error) {
35+
req *models.RevokeRoleRequest,
36+
) (*models.RevokeRoleResponse, error) {
3937
// Check for nil inputs
40-
if user == nil {
41-
return nil, fmt.Errorf("user cannot be nil")
42-
}
43-
if role == nil {
44-
return nil, fmt.Errorf("role cannot be nil")
38+
if !req.IsValid() {
39+
return nil, fmt.Errorf("user and role must be provided to revoke aws role")
4540
}
4641

42+
user := req.GetUser()
43+
role := req.GetRole()
44+
4745
// Determine if we should use IAM Identity Center or traditional IAM
4846
useIdentityCenter := p.shouldUseIdentityCenter(user)
4947

internal/providers/aws/rbac_iam.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,9 @@ import (
1515

1616
// authorizeRoleTraditionalIAM handles role authorization for traditional IAM users
1717
func (p *awsProvider) authorizeRoleTraditionalIAM(
18-
ctx context.Context, req *models.AuthorizeRoleRequest) (map[string]any, error) {
18+
ctx context.Context,
19+
req *models.AuthorizeRoleRequest,
20+
) (*models.AuthorizeRoleResponse, error) {
1921

2022
user := req.GetUser()
2123
role := req.GetRole()
@@ -46,7 +48,7 @@ func (p *awsProvider) authorizeRoleTraditionalIAM(
4648
}
4749

4850
// revokeRoleTraditionalIAM handles role revocation for traditional IAM users
49-
func (p *awsProvider) revokeRoleTraditionalIAM(ctx context.Context, user *models.User, role *models.Role) (map[string]any, error) {
51+
func (p *awsProvider) revokeRoleTraditionalIAM(ctx context.Context, user *models.User, role *models.Role) (*models.RevokeRoleResponse, error) {
5052

5153
// Check if the role exists
5254
existingRole, err := p.getRole(ctx, role)

internal/providers/aws/rbac_sso.go

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import (
1919
func (p *awsProvider) authorizeRoleIdentityCenter(
2020
ctx context.Context,
2121
req *models.AuthorizeRoleRequest,
22-
) (map[string]any, error) {
22+
) (*models.AuthorizeRoleResponse, error) {
2323

2424
user := req.GetUser()
2525
role := req.GetRole()
@@ -48,11 +48,13 @@ func (p *awsProvider) authorizeRoleIdentityCenter(
4848
return nil, fmt.Errorf("failed to create account assignment: %w", err)
4949
}
5050

51-
return map[string]any{
52-
"instanceArn": instanceArn,
53-
"permissionSetArn": permissionSetArn,
54-
"principalId": principalId,
55-
"accountId": p.GetAccountID(),
51+
return &models.AuthorizeRoleResponse{
52+
Metadata: map[string]any{
53+
"instanceArn": instanceArn,
54+
"permissionSetArn": permissionSetArn,
55+
"principalId": principalId,
56+
"accountId": p.GetAccountID(),
57+
},
5658
}, nil
5759
}
5860

internal/providers/azure/rbac.go

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
func (p *azureProvider) AuthorizeRole(
1212
ctx context.Context,
1313
req *models.AuthorizeRoleRequest,
14-
) (map[string]any, error) {
14+
) (*models.AuthorizeRoleResponse, error) {
1515

1616
if !req.IsValid() {
1717
return nil, fmt.Errorf("user and role must be provided to authorize azure role")
@@ -42,10 +42,16 @@ func (p *azureProvider) AuthorizeRole(
4242
// Revoke removes access for a user from a role
4343
func (p *azureProvider) RevokeRole(
4444
ctx context.Context,
45-
user *models.User,
46-
role *models.Role,
47-
metadata map[string]any,
48-
) (map[string]any, error) {
45+
req *models.RevokeRoleRequest,
46+
) (*models.RevokeRoleResponse, error) {
47+
48+
if !req.IsValid() {
49+
return nil, fmt.Errorf("user and role must be provided to revoke azure role")
50+
}
51+
52+
user := req.GetUser()
53+
role := req.GetRole()
54+
4955
// Get the role definition
5056
roleDefinition, err := p.getRoleDefinition(ctx, role.Name)
5157
if err != nil {

0 commit comments

Comments
 (0)