github.com/influxdata/influxdb/v2@v2.7.6/authz.go (about) 1 package influxdb 2 3 import ( 4 "errors" 5 "fmt" 6 "path" 7 8 "github.com/influxdata/influxdb/v2/kit/platform" 9 errors2 "github.com/influxdata/influxdb/v2/kit/platform/errors" 10 ) 11 12 var ( 13 // ErrAuthorizerNotSupported notes that the provided authorizer is not supported for the action you are trying to perform. 14 ErrAuthorizerNotSupported = errors.New("your authorizer is not supported, please use *platform.Authorization as authorizer") 15 // ErrInvalidResourceType notes that the provided resource is invalid 16 ErrInvalidResourceType = errors.New("unknown resource type for permission") 17 // ErrInvalidAction notes that the provided action is invalid 18 ErrInvalidAction = errors.New("unknown action for permission") 19 ) 20 21 // Authorizer will authorize a permission. 22 type Authorizer interface { 23 // PermissionSet returns the PermissionSet associated with the authorizer 24 PermissionSet() (PermissionSet, error) 25 26 // ID returns an identifier used for auditing. 27 Identifier() platform.ID 28 29 // GetUserID returns the user id. 30 GetUserID() platform.ID 31 32 // Kind metadata for auditing. 33 Kind() string 34 } 35 36 // PermissionAllowed determines if a permission is allowed. 37 func PermissionAllowed(perm Permission, ps []Permission) bool { 38 for _, p := range ps { 39 if p.Matches(perm) { 40 return true 41 } 42 } 43 return false 44 } 45 46 // Action is an enum defining all possible resource operations 47 type Action string 48 49 const ( 50 // ReadAction is the action for reading. 51 ReadAction Action = "read" // 1 52 // WriteAction is the action for writing. 53 WriteAction Action = "write" // 2 54 ) 55 56 var actions = []Action{ 57 ReadAction, // 1 58 WriteAction, // 2 59 } 60 61 // Valid checks if the action is a member of the Action enum 62 func (a Action) Valid() (err error) { 63 switch a { 64 case ReadAction: // 1 65 case WriteAction: // 2 66 default: 67 err = ErrInvalidAction 68 } 69 70 return err 71 } 72 73 // ResourceType is an enum defining all resource types that have a permission model in platform 74 type ResourceType string 75 76 // Resource is an authorizable resource. 77 type Resource struct { 78 Type ResourceType `json:"type"` 79 ID *platform.ID `json:"id,omitempty"` 80 OrgID *platform.ID `json:"orgID,omitempty"` 81 } 82 83 // String stringifies a resource 84 func (r Resource) String() string { 85 if r.OrgID != nil && r.ID != nil { 86 return path.Join(string(OrgsResourceType), r.OrgID.String(), string(r.Type), r.ID.String()) 87 } 88 89 if r.OrgID != nil { 90 return path.Join(string(OrgsResourceType), r.OrgID.String(), string(r.Type)) 91 } 92 93 if r.ID != nil { 94 return path.Join(string(r.Type), r.ID.String()) 95 } 96 97 return string(r.Type) 98 } 99 100 const ( 101 // AuthorizationsResourceType gives permissions to one or more authorizations. 102 AuthorizationsResourceType = ResourceType("authorizations") // 0 103 // BucketsResourceType gives permissions to one or more buckets. 104 BucketsResourceType = ResourceType("buckets") // 1 105 // DashboardsResourceType gives permissions to one or more dashboards. 106 DashboardsResourceType = ResourceType("dashboards") // 2 107 // OrgsResourceType gives permissions to one or more orgs. 108 OrgsResourceType = ResourceType("orgs") // 3 109 // SourcesResourceType gives permissions to one or more sources. 110 SourcesResourceType = ResourceType("sources") // 4 111 // TasksResourceType gives permissions to one or more tasks. 112 TasksResourceType = ResourceType("tasks") // 5 113 // TelegrafsResourceType type gives permissions to a one or more telegrafs. 114 TelegrafsResourceType = ResourceType("telegrafs") // 6 115 // UsersResourceType gives permissions to one or more users. 116 UsersResourceType = ResourceType("users") // 7 117 // VariablesResourceType gives permission to one or more variables. 118 VariablesResourceType = ResourceType("variables") // 8 119 // ScraperResourceType gives permission to one or more scrapers. 120 ScraperResourceType = ResourceType("scrapers") // 9 121 // SecretsResourceType gives permission to one or more secrets. 122 SecretsResourceType = ResourceType("secrets") // 10 123 // LabelsResourceType gives permission to one or more labels. 124 LabelsResourceType = ResourceType("labels") // 11 125 // ViewsResourceType gives permission to one or more views. 126 ViewsResourceType = ResourceType("views") // 12 127 // DocumentsResourceType gives permission to one or more documents. 128 DocumentsResourceType = ResourceType("documents") // 13 129 // NotificationRuleResourceType gives permission to one or more notificationRules. 130 NotificationRuleResourceType = ResourceType("notificationRules") // 14 131 // NotificationEndpointResourceType gives permission to one or more notificationEndpoints. 132 NotificationEndpointResourceType = ResourceType("notificationEndpoints") // 15 133 // ChecksResourceType gives permission to one or more Checks. 134 ChecksResourceType = ResourceType("checks") // 16 135 // DBRPType gives permission to one or more DBRPs. 136 DBRPResourceType = ResourceType("dbrp") // 17 137 // NotebooksResourceType gives permission to one or more notebooks. 138 NotebooksResourceType = ResourceType("notebooks") // 18 139 // AnnotationsResourceType gives permission to one or more annotations. 140 AnnotationsResourceType = ResourceType("annotations") // 19 141 // RemotesResourceType gives permission to one or more remote connections. 142 RemotesResourceType = ResourceType("remotes") // 20 143 // ReplicationsResourceType gives permission to one or more replications. 144 ReplicationsResourceType = ResourceType("replications") // 21 145 // InstanceResourceType is a special permission that allows ownership of the entire instance (creating orgs/operator tokens/etc) 146 InstanceResourceType = ResourceType("instance") // 22 147 ) 148 149 // AllResourceTypes is the list of all known resource types. 150 var AllResourceTypes = []ResourceType{ 151 AuthorizationsResourceType, // 0 152 BucketsResourceType, // 1 153 DashboardsResourceType, // 2 154 OrgsResourceType, // 3 155 SourcesResourceType, // 4 156 TasksResourceType, // 5 157 TelegrafsResourceType, // 6 158 UsersResourceType, // 7 159 VariablesResourceType, // 8 160 ScraperResourceType, // 9 161 SecretsResourceType, // 10 162 LabelsResourceType, // 11 163 ViewsResourceType, // 12 164 DocumentsResourceType, // 13 165 NotificationRuleResourceType, // 14 166 NotificationEndpointResourceType, // 15 167 ChecksResourceType, // 16 168 DBRPResourceType, // 17 169 NotebooksResourceType, // 18 170 AnnotationsResourceType, // 19 171 RemotesResourceType, // 20 172 ReplicationsResourceType, // 21 173 InstanceResourceType, // 22 174 // NOTE: when modifying this list, please update the swagger for components.schemas.Permission resource enum. 175 } 176 177 // Valid checks if the resource type is a member of the ResourceType enum. 178 func (r Resource) Valid() (err error) { 179 return r.Type.Valid() 180 } 181 182 // Valid checks if the resource type is a member of the ResourceType enum. 183 func (t ResourceType) Valid() (err error) { 184 switch t { 185 case AuthorizationsResourceType: // 0 186 case BucketsResourceType: // 1 187 case DashboardsResourceType: // 2 188 case OrgsResourceType: // 3 189 case TasksResourceType: // 4 190 case TelegrafsResourceType: // 5 191 case SourcesResourceType: // 6 192 case UsersResourceType: // 7 193 case VariablesResourceType: // 8 194 case ScraperResourceType: // 9 195 case SecretsResourceType: // 10 196 case LabelsResourceType: // 11 197 case ViewsResourceType: // 12 198 case DocumentsResourceType: // 13 199 case NotificationRuleResourceType: // 14 200 case NotificationEndpointResourceType: // 15 201 case ChecksResourceType: // 16 202 case DBRPResourceType: // 17 203 case NotebooksResourceType: // 18 204 case AnnotationsResourceType: // 19 205 case RemotesResourceType: // 20 206 case ReplicationsResourceType: // 21 207 case InstanceResourceType: // 22 208 default: 209 err = ErrInvalidResourceType 210 } 211 212 return err 213 } 214 215 type PermissionSet []Permission 216 217 func (ps PermissionSet) Allowed(p Permission) bool { 218 return PermissionAllowed(p, ps) 219 } 220 221 // Permission defines an action and a resource. 222 type Permission struct { 223 Action Action `json:"action"` 224 Resource Resource `json:"resource"` 225 } 226 227 // Matches returns whether or not one permission matches the other. 228 func (p Permission) Matches(perm Permission) bool { 229 return p.matchesV1(perm) 230 } 231 232 func (p Permission) matchesV1(perm Permission) bool { 233 if p.Action != perm.Action { 234 return false 235 } 236 237 if p.Resource.Type == InstanceResourceType { 238 return true 239 } 240 241 if p.Resource.Type != perm.Resource.Type { 242 return false 243 } 244 245 if p.Resource.OrgID == nil && p.Resource.ID == nil { 246 return true 247 } 248 249 if p.Resource.OrgID != nil && perm.Resource.OrgID != nil && p.Resource.ID != nil && perm.Resource.ID != nil { 250 if *p.Resource.OrgID != *perm.Resource.OrgID && *p.Resource.ID == *perm.Resource.ID { 251 fmt.Printf("v1: old match used: p.Resource.OrgID=%s perm.Resource.OrgID=%s p.Resource.ID=%s", 252 *p.Resource.OrgID, *perm.Resource.OrgID, *p.Resource.ID) 253 } 254 } 255 256 if p.Resource.OrgID != nil && p.Resource.ID == nil { 257 pOrgID := *p.Resource.OrgID 258 if perm.Resource.OrgID != nil { 259 permOrgID := *perm.Resource.OrgID 260 if pOrgID == permOrgID { 261 return true 262 } 263 } 264 } 265 266 if p.Resource.ID != nil { 267 pID := *p.Resource.ID 268 if perm.Resource.ID != nil { 269 permID := *perm.Resource.ID 270 if pID == permID { 271 return true 272 } 273 } 274 } 275 276 return false 277 } 278 279 func (p Permission) String() string { 280 return fmt.Sprintf("%s:%s", p.Action, p.Resource) 281 } 282 283 // Valid checks if there the resource and action provided is known. 284 func (p *Permission) Valid() error { 285 if err := p.Resource.Valid(); err != nil { 286 return &errors2.Error{ 287 Code: errors2.EInvalid, 288 Err: err, 289 Msg: "invalid resource type for permission", 290 } 291 } 292 293 if err := p.Action.Valid(); err != nil { 294 return &errors2.Error{ 295 Code: errors2.EInvalid, 296 Err: err, 297 Msg: "invalid action type for permission", 298 } 299 } 300 301 if p.Resource.OrgID != nil && !p.Resource.OrgID.Valid() { 302 return &errors2.Error{ 303 Code: errors2.EInvalid, 304 Err: platform.ErrInvalidID, 305 Msg: "invalid org id for permission", 306 } 307 } 308 309 if p.Resource.ID != nil && !p.Resource.ID.Valid() { 310 return &errors2.Error{ 311 Code: errors2.EInvalid, 312 Err: platform.ErrInvalidID, 313 Msg: "invalid id for permission", 314 } 315 } 316 317 return nil 318 } 319 320 // NewPermission returns a permission with provided arguments. 321 func NewPermission(a Action, rt ResourceType, orgID platform.ID) (*Permission, error) { 322 p := &Permission{ 323 Action: a, 324 Resource: Resource{ 325 Type: rt, 326 OrgID: &orgID, 327 }, 328 } 329 330 return p, p.Valid() 331 } 332 333 // NewResourcePermission returns a permission with provided arguments. 334 func NewResourcePermission(a Action, rt ResourceType, rid platform.ID) (*Permission, error) { 335 p := &Permission{ 336 Action: a, 337 Resource: Resource{ 338 Type: rt, 339 ID: &rid, 340 }, 341 } 342 343 return p, p.Valid() 344 } 345 346 // NewGlobalPermission constructs a global permission capable of accessing any resource of type rt. 347 func NewGlobalPermission(a Action, rt ResourceType) (*Permission, error) { 348 p := &Permission{ 349 Action: a, 350 Resource: Resource{ 351 Type: rt, 352 }, 353 } 354 return p, p.Valid() 355 } 356 357 // NewPermissionAtID creates a permission with the provided arguments. 358 func NewPermissionAtID(id platform.ID, a Action, rt ResourceType, orgID platform.ID) (*Permission, error) { 359 p := &Permission{ 360 Action: a, 361 Resource: Resource{ 362 Type: rt, 363 OrgID: &orgID, 364 ID: &id, 365 }, 366 } 367 368 return p, p.Valid() 369 } 370 371 // OperPermissions are the default permissions for those who setup the application. 372 func OperPermissions() []Permission { 373 ps := []Permission{} 374 for _, r := range AllResourceTypes { 375 // For now, we are only allowing instance permissions when logged in through session auth 376 // That is handled in user resource mapping 377 if r == InstanceResourceType { 378 continue 379 } 380 for _, a := range actions { 381 ps = append(ps, Permission{Action: a, Resource: Resource{Type: r}}) 382 } 383 } 384 385 return ps 386 } 387 388 // ReadAllPermissions represents permission to read all data and metadata. 389 // Like OperPermissions, but allows read-only users. 390 func ReadAllPermissions() []Permission { 391 ps := make([]Permission, len(AllResourceTypes)) 392 for i, t := range AllResourceTypes { 393 // For now, we are only allowing instance permissions when logged in through session auth 394 // That is handled in user resource mapping 395 if t == InstanceResourceType { 396 continue 397 } 398 ps[i] = Permission{Action: ReadAction, Resource: Resource{Type: t}} 399 } 400 return ps 401 } 402 403 // OwnerPermissions are the default permissions for those who own a resource. 404 func OwnerPermissions(orgID platform.ID) []Permission { 405 ps := []Permission{} 406 for _, r := range AllResourceTypes { 407 // For now, we are only allowing instance permissions when logged in through session auth 408 // That is handled in user resource mapping 409 if r == InstanceResourceType { 410 continue 411 } 412 for _, a := range actions { 413 if r == OrgsResourceType { 414 ps = append(ps, Permission{Action: a, Resource: Resource{Type: r, ID: &orgID}}) 415 continue 416 } 417 ps = append(ps, Permission{Action: a, Resource: Resource{Type: r, OrgID: &orgID}}) 418 } 419 } 420 return ps 421 } 422 423 // MePermissions is the permission to read/write myself. 424 func MePermissions(userID platform.ID) []Permission { 425 ps := []Permission{} 426 for _, a := range actions { 427 ps = append(ps, Permission{Action: a, Resource: Resource{Type: UsersResourceType, ID: &userID}}) 428 } 429 430 return ps 431 } 432 433 // MemberPermissions are the default permissions for those who can see a resource. 434 func MemberPermissions(orgID platform.ID) []Permission { 435 ps := []Permission{} 436 for _, r := range AllResourceTypes { 437 // For now, we are only allowing instance permissions when logged in through session auth 438 // That is handled in user resource mapping 439 if r == InstanceResourceType { 440 continue 441 } 442 if r == OrgsResourceType { 443 ps = append(ps, Permission{Action: ReadAction, Resource: Resource{Type: r, ID: &orgID}}) 444 continue 445 } 446 ps = append(ps, Permission{Action: ReadAction, Resource: Resource{Type: r, OrgID: &orgID}}) 447 } 448 449 return ps 450 } 451 452 // MemberPermissions are the default permissions for those who can see a resource. 453 func MemberBucketPermission(bucketID platform.ID) Permission { 454 return Permission{Action: ReadAction, Resource: Resource{Type: BucketsResourceType, ID: &bucketID}} 455 }