@@ -815,6 +815,86 @@ func (q *querier) customRoleEscalationCheck(ctx context.Context, actor rbac.Subj
815
815
return nil
816
816
}
817
817
818
+ // customRoleCheck will validate a custom role for inserting or updating.
819
+ // If the role is not valid, an error will be returned.
820
+ // - Check custom roles are valid for their resource types + actions
821
+ // - Check the actor can create the custom role
822
+ // - Check the custom role does not grant perms the actor does not have
823
+ // - Prevent negative perms
824
+ // - Prevent roles with site and org permissions.
825
+ func (q * querier ) customRoleCheck (ctx context.Context , role database.CustomRole ) error {
826
+ act , ok := ActorFromContext (ctx )
827
+ if ! ok {
828
+ return NoActorError
829
+ }
830
+
831
+ // Org permissions require an org role
832
+ if role .OrganizationID .UUID == uuid .Nil && len (role .OrgPermissions ) > 0 {
833
+ return xerrors .Errorf ("organization permissions require specifying an organization id" )
834
+ }
835
+
836
+ // Org roles can only specify org permissions
837
+ if role .OrganizationID .UUID != uuid .Nil && (len (role .SitePermissions ) > 0 || len (role .UserPermissions ) > 0 ) {
838
+ return xerrors .Errorf ("organization roles specify site or user permissions" )
839
+ }
840
+
841
+ // The rbac.Role has a 'Valid()' function on it that will do a lot
842
+ // of checks.
843
+ rbacRole , err := rolestore .ConvertDBRole (database.CustomRole {
844
+ Name : role .Name ,
845
+ DisplayName : role .DisplayName ,
846
+ SitePermissions : role .SitePermissions ,
847
+ OrgPermissions : role .OrgPermissions ,
848
+ UserPermissions : role .UserPermissions ,
849
+ OrganizationID : role .OrganizationID ,
850
+ })
851
+ if err != nil {
852
+ return xerrors .Errorf ("invalid args: %w" , err )
853
+ }
854
+
855
+ err = rbacRole .Valid ()
856
+ if err != nil {
857
+ return xerrors .Errorf ("invalid role: %w" , err )
858
+ }
859
+
860
+ if len (rbacRole .Org ) > 0 && len (rbacRole .Site ) > 0 {
861
+ // This is a choice to keep roles simple. If we allow mixing site and org scoped perms, then knowing who can
862
+ // do what gets more complicated.
863
+ return xerrors .Errorf ("invalid custom role, cannot assign both org and site permissions at the same time" )
864
+ }
865
+
866
+ if len (rbacRole .Org ) > 1 {
867
+ // Again to avoid more complexity in our roles
868
+ return xerrors .Errorf ("invalid custom role, cannot assign permissions to more than 1 org at a time" )
869
+ }
870
+
871
+ // Prevent escalation
872
+ for _ , sitePerm := range rbacRole .Site {
873
+ err := q .customRoleEscalationCheck (ctx , act , sitePerm , rbac.Object {Type : sitePerm .ResourceType })
874
+ if err != nil {
875
+ return xerrors .Errorf ("site permission: %w" , err )
876
+ }
877
+ }
878
+
879
+ for orgID , perms := range rbacRole .Org {
880
+ for _ , orgPerm := range perms {
881
+ err := q .customRoleEscalationCheck (ctx , act , orgPerm , rbac.Object {OrgID : orgID , Type : orgPerm .ResourceType })
882
+ if err != nil {
883
+ return xerrors .Errorf ("org=%q: %w" , orgID , err )
884
+ }
885
+ }
886
+ }
887
+
888
+ for _ , userPerm := range rbacRole .User {
889
+ err := q .customRoleEscalationCheck (ctx , act , userPerm , rbac.Object {Type : userPerm .ResourceType , Owner : act .ID })
890
+ if err != nil {
891
+ return xerrors .Errorf ("user permission: %w" , err )
892
+ }
893
+ }
894
+
895
+ return nil
896
+ }
897
+
818
898
func (q * querier ) AcquireLock (ctx context.Context , id int64 ) error {
819
899
return q .db .AcquireLock (ctx , id )
820
900
}
@@ -2579,86 +2659,6 @@ func (q *querier) InsertCustomRole(ctx context.Context, arg database.InsertCusto
2579
2659
return q .db .InsertCustomRole (ctx , arg )
2580
2660
}
2581
2661
2582
- // customRoleCheck will validate a custom role for inserting or updating.
2583
- // If the role is not valid, an error will be returned.
2584
- // - Check custom roles are valid for their resource types + actions
2585
- // - Check the actor can create the custom role
2586
- // - Check the custom role does not grant perms the actor does not have
2587
- // - Prevent negative perms
2588
- // - Prevent roles with site and org permissions.
2589
- func (q * querier ) customRoleCheck (ctx context.Context , role database.CustomRole ) error {
2590
- act , ok := ActorFromContext (ctx )
2591
- if ! ok {
2592
- return NoActorError
2593
- }
2594
-
2595
- // Org permissions require an org role
2596
- if role .OrganizationID .UUID == uuid .Nil && len (role .OrgPermissions ) > 0 {
2597
- return xerrors .Errorf ("organization permissions require specifying an organization id" )
2598
- }
2599
-
2600
- // Org roles can only specify org permissions
2601
- if role .OrganizationID .UUID != uuid .Nil && (len (role .SitePermissions ) > 0 || len (role .UserPermissions ) > 0 ) {
2602
- return xerrors .Errorf ("organization roles specify site or user permissions" )
2603
- }
2604
-
2605
- // The rbac.Role has a 'Valid()' function on it that will do a lot
2606
- // of checks.
2607
- rbacRole , err := rolestore .ConvertDBRole (database.CustomRole {
2608
- Name : role .Name ,
2609
- DisplayName : role .DisplayName ,
2610
- SitePermissions : role .SitePermissions ,
2611
- OrgPermissions : role .OrgPermissions ,
2612
- UserPermissions : role .UserPermissions ,
2613
- OrganizationID : role .OrganizationID ,
2614
- })
2615
- if err != nil {
2616
- return xerrors .Errorf ("invalid args: %w" , err )
2617
- }
2618
-
2619
- err = rbacRole .Valid ()
2620
- if err != nil {
2621
- return xerrors .Errorf ("invalid role: %w" , err )
2622
- }
2623
-
2624
- if len (rbacRole .Org ) > 0 && len (rbacRole .Site ) > 0 {
2625
- // This is a choice to keep roles simple. If we allow mixing site and org scoped perms, then knowing who can
2626
- // do what gets more complicated.
2627
- return xerrors .Errorf ("invalid custom role, cannot assign both org and site permissions at the same time" )
2628
- }
2629
-
2630
- if len (rbacRole .Org ) > 1 {
2631
- // Again to avoid more complexity in our roles
2632
- return xerrors .Errorf ("invalid custom role, cannot assign permissions to more than 1 org at a time" )
2633
- }
2634
-
2635
- // Prevent escalation
2636
- for _ , sitePerm := range rbacRole .Site {
2637
- err := q .customRoleEscalationCheck (ctx , act , sitePerm , rbac.Object {Type : sitePerm .ResourceType })
2638
- if err != nil {
2639
- return xerrors .Errorf ("site permission: %w" , err )
2640
- }
2641
- }
2642
-
2643
- for orgID , perms := range rbacRole .Org {
2644
- for _ , orgPerm := range perms {
2645
- err := q .customRoleEscalationCheck (ctx , act , orgPerm , rbac.Object {OrgID : orgID , Type : orgPerm .ResourceType })
2646
- if err != nil {
2647
- return xerrors .Errorf ("org=%q: %w" , orgID , err )
2648
- }
2649
- }
2650
- }
2651
-
2652
- for _ , userPerm := range rbacRole .User {
2653
- err := q .customRoleEscalationCheck (ctx , act , userPerm , rbac.Object {Type : userPerm .ResourceType , Owner : act .ID })
2654
- if err != nil {
2655
- return xerrors .Errorf ("user permission: %w" , err )
2656
- }
2657
- }
2658
-
2659
- return nil
2660
- }
2661
-
2662
2662
func (q * querier ) InsertDBCryptKey (ctx context.Context , arg database.InsertDBCryptKeyParams ) error {
2663
2663
if err := q .authorizeContext (ctx , policy .ActionCreate , rbac .ResourceSystem ); err != nil {
2664
2664
return err
@@ -3111,7 +3111,30 @@ func (q *querier) UpdateAPIKeyByID(ctx context.Context, arg database.UpdateAPIKe
3111
3111
}
3112
3112
3113
3113
func (q * querier ) UpdateCustomRole (ctx context.Context , arg database.UpdateCustomRoleParams ) (database.CustomRole , error ) {
3114
- panic ("not implemented" )
3114
+ if arg .OrganizationID .UUID != uuid .Nil {
3115
+ if err := q .authorizeContext (ctx , policy .ActionUpdate , rbac .ResourceAssignOrgRole .InOrg (arg .OrganizationID .UUID )); err != nil {
3116
+ return database.CustomRole {}, err
3117
+ }
3118
+ } else {
3119
+ if err := q .authorizeContext (ctx , policy .ActionUpdate , rbac .ResourceAssignRole ); err != nil {
3120
+ return database.CustomRole {}, err
3121
+ }
3122
+ }
3123
+
3124
+ if err := q .customRoleCheck (ctx , database.CustomRole {
3125
+ Name : arg .Name ,
3126
+ DisplayName : arg .DisplayName ,
3127
+ SitePermissions : arg .SitePermissions ,
3128
+ OrgPermissions : arg .OrgPermissions ,
3129
+ UserPermissions : arg .UserPermissions ,
3130
+ CreatedAt : time .Now (),
3131
+ UpdatedAt : time .Now (),
3132
+ OrganizationID : arg .OrganizationID ,
3133
+ ID : uuid .New (),
3134
+ }); err != nil {
3135
+ return database.CustomRole {}, err
3136
+ }
3137
+ return q .db .UpdateCustomRole (ctx , arg )
3115
3138
}
3116
3139
3117
3140
func (q * querier ) UpdateExternalAuthLink (ctx context.Context , arg database.UpdateExternalAuthLinkParams ) (database.ExternalAuthLink , error ) {
0 commit comments