@@ -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
}
@@ -2571,86 +2651,6 @@ func (q *querier) InsertCustomRole(ctx context.Context, arg database.InsertCusto
2571
2651
return q .db .InsertCustomRole (ctx , arg )
2572
2652
}
2573
2653
2574
- // customRoleCheck will validate a custom role for inserting or updating.
2575
- // If the role is not valid, an error will be returned.
2576
- // - Check custom roles are valid for their resource types + actions
2577
- // - Check the actor can create the custom role
2578
- // - Check the custom role does not grant perms the actor does not have
2579
- // - Prevent negative perms
2580
- // - Prevent roles with site and org permissions.
2581
- func (q * querier ) customRoleCheck (ctx context.Context , role database.CustomRole ) error {
2582
- act , ok := ActorFromContext (ctx )
2583
- if ! ok {
2584
- return NoActorError
2585
- }
2586
-
2587
- // Org permissions require an org role
2588
- if role .OrganizationID .UUID == uuid .Nil && len (role .OrgPermissions ) > 0 {
2589
- return xerrors .Errorf ("organization permissions require specifying an organization id" )
2590
- }
2591
-
2592
- // Org roles can only specify org permissions
2593
- if role .OrganizationID .UUID != uuid .Nil && (len (role .SitePermissions ) > 0 || len (role .UserPermissions ) > 0 ) {
2594
- return xerrors .Errorf ("organization roles specify site or user permissions" )
2595
- }
2596
-
2597
- // The rbac.Role has a 'Valid()' function on it that will do a lot
2598
- // of checks.
2599
- rbacRole , err := rolestore .ConvertDBRole (database.CustomRole {
2600
- Name : role .Name ,
2601
- DisplayName : role .DisplayName ,
2602
- SitePermissions : role .SitePermissions ,
2603
- OrgPermissions : role .OrgPermissions ,
2604
- UserPermissions : role .UserPermissions ,
2605
- OrganizationID : role .OrganizationID ,
2606
- })
2607
- if err != nil {
2608
- return xerrors .Errorf ("invalid args: %w" , err )
2609
- }
2610
-
2611
- err = rbacRole .Valid ()
2612
- if err != nil {
2613
- return xerrors .Errorf ("invalid role: %w" , err )
2614
- }
2615
-
2616
- if len (rbacRole .Org ) > 0 && len (rbacRole .Site ) > 0 {
2617
- // This is a choice to keep roles simple. If we allow mixing site and org scoped perms, then knowing who can
2618
- // do what gets more complicated.
2619
- return xerrors .Errorf ("invalid custom role, cannot assign both org and site permissions at the same time" )
2620
- }
2621
-
2622
- if len (rbacRole .Org ) > 1 {
2623
- // Again to avoid more complexity in our roles
2624
- return xerrors .Errorf ("invalid custom role, cannot assign permissions to more than 1 org at a time" )
2625
- }
2626
-
2627
- // Prevent escalation
2628
- for _ , sitePerm := range rbacRole .Site {
2629
- err := q .customRoleEscalationCheck (ctx , act , sitePerm , rbac.Object {Type : sitePerm .ResourceType })
2630
- if err != nil {
2631
- return xerrors .Errorf ("site permission: %w" , err )
2632
- }
2633
- }
2634
-
2635
- for orgID , perms := range rbacRole .Org {
2636
- for _ , orgPerm := range perms {
2637
- err := q .customRoleEscalationCheck (ctx , act , orgPerm , rbac.Object {OrgID : orgID , Type : orgPerm .ResourceType })
2638
- if err != nil {
2639
- return xerrors .Errorf ("org=%q: %w" , orgID , err )
2640
- }
2641
- }
2642
- }
2643
-
2644
- for _ , userPerm := range rbacRole .User {
2645
- err := q .customRoleEscalationCheck (ctx , act , userPerm , rbac.Object {Type : userPerm .ResourceType , Owner : act .ID })
2646
- if err != nil {
2647
- return xerrors .Errorf ("user permission: %w" , err )
2648
- }
2649
- }
2650
-
2651
- return nil
2652
- }
2653
-
2654
2654
func (q * querier ) InsertDBCryptKey (ctx context.Context , arg database.InsertDBCryptKeyParams ) error {
2655
2655
if err := q .authorizeContext (ctx , policy .ActionCreate , rbac .ResourceSystem ); err != nil {
2656
2656
return err
@@ -3103,7 +3103,30 @@ func (q *querier) UpdateAPIKeyByID(ctx context.Context, arg database.UpdateAPIKe
3103
3103
}
3104
3104
3105
3105
func (q * querier ) UpdateCustomRole (ctx context.Context , arg database.UpdateCustomRoleParams ) (database.CustomRole , error ) {
3106
- panic ("not implemented" )
3106
+ if arg .OrganizationID .UUID != uuid .Nil {
3107
+ if err := q .authorizeContext (ctx , policy .ActionUpdate , rbac .ResourceAssignOrgRole .InOrg (arg .OrganizationID .UUID )); err != nil {
3108
+ return database.CustomRole {}, err
3109
+ }
3110
+ } else {
3111
+ if err := q .authorizeContext (ctx , policy .ActionUpdate , rbac .ResourceAssignRole ); err != nil {
3112
+ return database.CustomRole {}, err
3113
+ }
3114
+ }
3115
+
3116
+ if err := q .customRoleCheck (ctx , database.CustomRole {
3117
+ Name : arg .Name ,
3118
+ DisplayName : arg .DisplayName ,
3119
+ SitePermissions : arg .SitePermissions ,
3120
+ OrgPermissions : arg .OrgPermissions ,
3121
+ UserPermissions : arg .UserPermissions ,
3122
+ CreatedAt : time .Now (),
3123
+ UpdatedAt : time .Now (),
3124
+ OrganizationID : arg .OrganizationID ,
3125
+ ID : uuid .New (),
3126
+ }); err != nil {
3127
+ return database.CustomRole {}, err
3128
+ }
3129
+ return q .db .UpdateCustomRole (ctx , arg )
3107
3130
}
3108
3131
3109
3132
func (q * querier ) UpdateExternalAuthLink (ctx context.Context , arg database.UpdateExternalAuthLinkParams ) (database.ExternalAuthLink , error ) {
0 commit comments