github.com/greenpau/go-authcrunch@v1.0.50/pkg/user/user.go (about) 1 // Copyright 2022 Paul Greenberg greenpau@outlook.com 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package user 16 17 import ( 18 "encoding/json" 19 "fmt" 20 "github.com/greenpau/go-authcrunch/pkg/errors" 21 cfgutil "github.com/greenpau/go-authcrunch/pkg/util/cfg" 22 datautil "github.com/greenpau/go-authcrunch/pkg/util/data" 23 "strings" 24 "time" 25 ) 26 27 /* 28 var reservedFields = map[string]interface{}{ 29 "email": true, 30 "role": true, 31 "groups": true, 32 "group": true, 33 "app_metadata": true, 34 "realm_access": true, 35 "paths": true, 36 "acl": true, 37 } 38 */ 39 40 // User is a user with claims and status. 41 type User struct { 42 Claims *Claims `json:"claims,omitempty" xml:"claims,omitempty" yaml:"claims,omitempty"` 43 Token string `json:"token,omitempty" xml:"token,omitempty" yaml:"token,omitempty"` 44 TokenName string `json:"token_name,omitempty" xml:"token_name,omitempty" yaml:"token_name,omitempty"` 45 TokenSource string `json:"token_source,omitempty" xml:"token_source,omitempty" yaml:"token_source,omitempty"` 46 Authenticator Authenticator `json:"authenticator,omitempty" xml:"authenticator,omitempty" yaml:"authenticator,omitempty"` 47 Checkpoints []*Checkpoint `json:"checkpoints,omitempty" xml:"checkpoints,omitempty" yaml:"checkpoints,omitempty"` 48 Authorized bool `json:"authorized,omitempty" xml:"authorized,omitempty" yaml:"authorized,omitempty"` 49 FrontendLinks []string `json:"frontend_links,omitempty" xml:"frontend_links,omitempty" yaml:"frontend_links,omitempty"` 50 Locked bool `json:"locked,omitempty" xml:"locked,omitempty" yaml:"locked,omitempty"` 51 Cached bool `json:"cached,omitempty" xml:"cached,omitempty" yaml:"cached,omitempty"` 52 requestHeaders map[string]string 53 requestIdentity map[string]interface{} 54 // Holds the map for all the claims parsed from a token. 55 mkv map[string]interface{} 56 // Holds the map for a subset of claims necessary for ACL evaluation. 57 tkv map[string]interface{} 58 // Holds the map of the user roles. 59 rkv map[string]interface{} 60 } 61 62 // Checkpoint represents additional checks that a user needs to pass. Once 63 // a user passes the checks, the Authorized is set to true. The checks 64 // could be the acceptance of the terms of use, multi-factor authentication, 65 // etc. 66 type Checkpoint struct { 67 ID int `json:"id,omitempty" xml:"id,omitempty" yaml:"id,omitempty"` 68 Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"` 69 Type string `json:"type,omitempty" xml:"type,omitempty" yaml:"type,omitempty"` 70 Parameters string `json:"parameters,omitempty" xml:"parameters,omitempty" yaml:"parameters,omitempty"` 71 Passed bool `json:"passed,omitempty" xml:"passed,omitempty" yaml:"passed,omitempty"` 72 FailedAttempts int `json:"failed_attempts,omitempty" xml:"failed_attempts,omitempty" yaml:"failed_attempts,omitempty"` 73 } 74 75 // Authenticator represents authentication backend 76 type Authenticator struct { 77 Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"` 78 Realm string `json:"realm,omitempty" xml:"realm,omitempty" yaml:"realm,omitempty"` 79 Method string `json:"method,omitempty" xml:"method,omitempty" yaml:"method,omitempty"` 80 TempSecret string `json:"temp_secret,omitempty" xml:"temp_secret,omitempty" yaml:"temp_secret,omitempty"` 81 TempSessionID string `json:"temp_session_id,omitempty" xml:"temp_session_id,omitempty" yaml:"temp_session_id,omitempty"` 82 TempChallenge string `json:"temp_challenge,omitempty" xml:"temp_challenge,omitempty" yaml:"temp_challenge,omitempty"` 83 URL string `json:"url,omitempty" xml:"url,omitempty" yaml:"url,omitempty"` 84 } 85 86 // Claims represents custom and standard JWT claims associated with User. 87 type Claims struct { 88 Audience []string `json:"aud,omitempty" xml:"aud,omitempty" yaml:"aud,omitempty"` 89 ExpiresAt int64 `json:"exp,omitempty" xml:"exp,omitempty" yaml:"exp,omitempty"` 90 ID string `json:"jti,omitempty" xml:"jti,omitempty" yaml:"jti,omitempty"` 91 IssuedAt int64 `json:"iat,omitempty" xml:"iat,omitempty" yaml:"iat,omitempty"` 92 Issuer string `json:"iss,omitempty" xml:"iss,omitempty" yaml:"iss,omitempty"` 93 NotBefore int64 `json:"nbf,omitempty" xml:"nbf,omitempty" yaml:"nbf,omitempty"` 94 Subject string `json:"sub,omitempty" xml:"sub,omitempty" yaml:"sub,omitempty"` 95 Name string `json:"name,omitempty" xml:"name,omitempty" yaml:"name,omitempty"` 96 Email string `json:"email,omitempty" xml:"email,omitempty" yaml:"email,omitempty"` 97 Roles []string `json:"roles,omitempty" xml:"roles,omitempty" yaml:"roles,omitempty"` 98 Origin string `json:"origin,omitempty" xml:"origin,omitempty" yaml:"origin,omitempty"` 99 Scopes []string `json:"scopes,omitempty" xml:"scopes,omitempty" yaml:"scopes,omitempty"` 100 Organizations []string `json:"org,omitempty" xml:"org,omitempty" yaml:"org,omitempty"` 101 AccessList *AccessListClaim `json:"acl,omitempty" xml:"acl,omitempty" yaml:"acl,omitempty"` 102 Address string `json:"addr,omitempty" xml:"addr,omitempty" yaml:"addr,omitempty"` 103 PictureURL string `json:"picture,omitempty" xml:"picture,omitempty" yaml:"picture,omitempty"` 104 Metadata map[string]interface{} `json:"metadata,omitempty" xml:"metadata,omitempty" yaml:"metadata,omitempty"` 105 custom map[string]interface{} 106 } 107 108 // AccessListClaim represents custom acl/paths claim 109 type AccessListClaim struct { 110 Paths map[string]interface{} `json:"paths,omitempty" xml:"paths,omitempty" yaml:"paths,omitempty"` 111 } 112 113 // Valid validates user claims. 114 func (c Claims) Valid() error { 115 if c.ExpiresAt < time.Now().Unix() { 116 return errors.ErrExpiredToken 117 } 118 return nil 119 } 120 121 /* 122 func (c *Claims) MarshalJSON() ([]byte, error) { 123 m := make(map[string]interface{}) 124 if len(c.Audience) > 0 { 125 m["aud"] = c.Audience 126 } 127 if c.ExpiresAt > 0 { 128 m["exp"] = c.ExpiresAt 129 } 130 if c.IssuedAt > 0 { 131 m["iat"] = c.IssuedAt 132 } 133 if c.NotBefore > 0 { 134 m["nbf"] = c.NotBefore 135 } 136 if c.ID != "" { 137 m["jti"] = c.ID 138 } 139 if c.Issuer != "" { 140 m["iss"] = c.Issuer 141 } 142 if c.Subject != "" { 143 m["sub"] = c.Subject 144 } 145 if c.Name != "" { 146 m["sub"] = c.Name 147 } 148 if c.Email != "" { 149 m["email"] = c.Email 150 } 151 if len(c.Roles) > 0 { 152 m["roles"] = c.Roles 153 } 154 if c.Origin != "" { 155 m["origin"] = c.Origin 156 } 157 if len(c.Scopes) > 0 { 158 m["scopes"] = c.Scopes 159 } 160 if len(c.Organizations) > 0 { 161 m["org"] = c.Organizations 162 } 163 if c.AccessList != nil { 164 m["acl"] = c.AccessList 165 } 166 if c.Address != "" { 167 m["addr"] = c.Address 168 } 169 if c.PictureURL != "" { 170 m["picture"] = c.PictureURL 171 } 172 if c.Metadata != nil { 173 m["metadata"] = c.Metadata 174 } 175 if c.custom != nil { 176 for k, v := range c.custom { 177 m[k] = v 178 } 179 } 180 j, err := json.Marshal(m) 181 if err != nil { 182 return nil, err 183 } 184 return j, nil 185 } 186 */ 187 188 // AsMap converts Claims struct to dictionary. 189 func (u *User) AsMap() map[string]interface{} { 190 return u.mkv 191 } 192 193 // GetData return user claim felds and their values for the evaluation by an ACL. 194 func (u *User) GetData() map[string]interface{} { 195 return u.tkv 196 } 197 198 // SetRequestHeaders sets request headers associated with the user. 199 func (u *User) SetRequestHeaders(m map[string]string) { 200 u.requestHeaders = m 201 return 202 } 203 204 // GetRequestHeaders returns request headers associated with the user. 205 func (u *User) GetRequestHeaders() map[string]string { 206 return u.requestHeaders 207 } 208 209 // SetRequestIdentity sets request identity associated with the user. 210 func (u *User) SetRequestIdentity(m map[string]interface{}) { 211 u.requestIdentity = m 212 return 213 } 214 215 // GetRequestIdentity returns request identity associated with the user. 216 func (u *User) GetRequestIdentity() map[string]interface{} { 217 return u.requestIdentity 218 } 219 220 // BuildRequestIdentity builds request identity associated with the user. 221 func (u *User) BuildRequestIdentity(s string) map[string]interface{} { 222 m := make(map[string]interface{}) 223 m["roles"] = strings.Join(u.Claims.Roles, " ") 224 if u.Claims.ID != "" { 225 m["claim_id"] = u.Claims.ID 226 } 227 if u.Claims.Subject != "" { 228 m["sub"] = u.Claims.Subject 229 } 230 if u.Claims.Email != "" { 231 m["email"] = u.Claims.Email 232 } 233 234 switch s { 235 case "sub", "subject": 236 m["id"] = u.Claims.Subject 237 case "id": 238 m["id"] = u.Claims.ID 239 default: 240 if u.Claims.Email == "" { 241 m["id"] = u.Claims.Subject 242 } else { 243 m["id"] = u.Claims.Email 244 } 245 } 246 247 if u.Claims.Name != "" { 248 m["name"] = u.Claims.Name 249 } 250 if u.Claims.Email != "" { 251 m["email"] = u.Claims.Email 252 } 253 254 u.SetRequestIdentity(m) 255 return m 256 } 257 258 // SetExpiresAtClaim sets ExpiresAt claim. 259 func (u *User) SetExpiresAtClaim(i int64) { 260 u.Claims.ExpiresAt = i 261 u.mkv["exp"] = i 262 } 263 264 // SetIssuedAtClaim sets IssuedAt claim. 265 func (u *User) SetIssuedAtClaim(i int64) { 266 u.Claims.IssuedAt = i 267 u.mkv["iat"] = i 268 } 269 270 // SetNotBeforeClaim sets NotBefore claim. 271 func (u *User) SetNotBeforeClaim(i int64) { 272 u.Claims.NotBefore = i 273 u.mkv["nbf"] = i 274 } 275 276 // SetRolesClaim sets Roles claim 277 func (u *User) SetRolesClaim(roles []string) { 278 u.Claims.Roles = roles 279 u.tkv["roles"] = roles 280 u.mkv["roles"] = roles 281 for k := range u.rkv { 282 delete(u.rkv, k) 283 } 284 for _, roleName := range roles { 285 u.rkv[roleName] = true 286 } 287 } 288 289 // HasRole checks whether a user has any of the provided roles. 290 func (u *User) HasRole(roles ...string) bool { 291 for _, role := range roles { 292 if _, exists := u.rkv[role]; exists { 293 return true 294 } 295 } 296 return false 297 } 298 299 // HasRoles checks whether a user has all of the provided roles. 300 func (u *User) HasRoles(roles ...string) bool { 301 for _, role := range roles { 302 if _, exists := u.rkv[role]; !exists { 303 return false 304 } 305 } 306 return true 307 } 308 309 // AddFrontendLinks adds frontend links to User instance. 310 func (u *User) AddFrontendLinks(v interface{}) error { 311 var entries []string 312 switch data := v.(type) { 313 case string: 314 entries = append(entries, data) 315 case []string: 316 entries = data 317 case []interface{}: 318 for _, entry := range data { 319 switch entry.(type) { 320 case string: 321 entries = append(entries, entry.(string)) 322 default: 323 return errors.ErrCheckpointInvalidType.WithArgs(data, data) 324 } 325 } 326 default: 327 return errors.ErrFrontendLinkInvalidType.WithArgs(data, data) 328 } 329 m := make(map[string]bool) 330 for _, entry := range entries { 331 m[entry] = true 332 } 333 for _, link := range u.FrontendLinks { 334 if _, exists := m[link]; exists { 335 m[link] = false 336 } 337 } 338 for _, entry := range entries { 339 if m[entry] { 340 u.FrontendLinks = append(u.FrontendLinks, entry) 341 } 342 } 343 return nil 344 } 345 346 // GetClaimValueByField returns the value of the provides claims field. 347 func (u *User) GetClaimValueByField(k string) string { 348 if u.mkv == nil { 349 return "" 350 } 351 data := datautil.GetValueFromMapByPath(k, u.mkv) 352 switch v := data.(type) { 353 case string: 354 return v 355 case []string: 356 return strings.Join(v, ", ") 357 case []interface{}: 358 var entries []string 359 for _, entry := range v { 360 switch s := entry.(type) { 361 case string: 362 entries = append(entries, s) 363 } 364 } 365 return strings.Join(entries, ", ") 366 } 367 return fmt.Sprintf("%v", data) 368 } 369 370 // NewCheckpoints returns Checkpoint instances. 371 func NewCheckpoints(v interface{}) ([]*Checkpoint, error) { 372 var entries []string 373 checkpoints := []*Checkpoint{} 374 switch data := v.(type) { 375 case string: 376 entries = append(entries, data) 377 case []string: 378 entries = data 379 case []interface{}: 380 for _, entry := range data { 381 switch entry.(type) { 382 case string: 383 entries = append(entries, entry.(string)) 384 default: 385 return nil, errors.ErrCheckpointInvalidType.WithArgs(data, data) 386 } 387 } 388 default: 389 return nil, errors.ErrCheckpointInvalidType.WithArgs(data, data) 390 } 391 for i, entry := range entries { 392 c, err := NewCheckpoint(entry) 393 if err != nil { 394 return nil, errors.ErrCheckpointInvalidInput.WithArgs(entry, err) 395 } 396 c.ID = i 397 checkpoints = append(checkpoints, c) 398 } 399 if len(checkpoints) < 1 { 400 return nil, errors.ErrCheckpointEmpty 401 } 402 return checkpoints, nil 403 } 404 405 // NewCheckpoint returns Checkpoint instance. 406 func NewCheckpoint(s string) (*Checkpoint, error) { 407 c := &Checkpoint{} 408 args, err := cfgutil.DecodeArgs(s) 409 if err != nil { 410 return nil, err 411 } 412 if len(args) < 1 { 413 return nil, fmt.Errorf("too short") 414 } 415 if args[0] == "require" { 416 args = args[1:] 417 } 418 if len(args) < 1 { 419 return nil, fmt.Errorf("too short") 420 } 421 422 switch args[0] { 423 case "mfa": 424 c.Name = "Multi-factor authentication" 425 c.Type = "mfa" 426 case "password": 427 c.Name = "Authenticate with password" 428 c.Type = "password" 429 //case "consent": 430 // c.Name = "Acceptance and consent" 431 // c.Type = "consent" 432 default: 433 return nil, fmt.Errorf("unsupported keyword: %s", args[0]) 434 } 435 return c, nil 436 } 437 438 func unpackUserData(data interface{}) (map[string]interface{}, error) { 439 var m map[string]interface{} 440 switch v := data.(type) { 441 case string: 442 if err := json.Unmarshal([]byte(v), &m); err != nil { 443 return nil, err 444 } 445 case []uint8: 446 if err := json.Unmarshal(v, &m); err != nil { 447 return nil, err 448 } 449 case map[string]interface{}: 450 m = v 451 } 452 453 if len(m) == 0 { 454 return nil, errors.ErrInvalidUserDataType 455 } 456 return m, nil 457 } 458 459 func (c *Claims) unpackAudience(k string, v interface{}, mkv, tkv map[string]interface{}) error { 460 switch audiences := v.(type) { 461 case string: 462 c.Audience = append(c.Audience, audiences) 463 case []interface{}: 464 for _, audience := range audiences { 465 switch audience.(type) { 466 case string: 467 c.Audience = append(c.Audience, audience.(string)) 468 default: 469 return errors.ErrInvalidAudience.WithArgs(audience) 470 } 471 } 472 case []string: 473 for _, audience := range audiences { 474 c.Audience = append(c.Audience, audience) 475 } 476 default: 477 return errors.ErrInvalidAudienceType.WithArgs(v) 478 } 479 switch len(c.Audience) { 480 case 0: 481 case 1: 482 tkv[k] = c.Audience 483 mkv[k] = c.Audience[0] 484 default: 485 tkv[k] = c.Audience 486 mkv[k] = c.Audience 487 } 488 return nil 489 } 490 491 func (c *Claims) unpackExpiresAt(k string, v interface{}, mkv map[string]interface{}) error { 492 switch exp := v.(type) { 493 case float64: 494 c.ExpiresAt = int64(exp) 495 case int: 496 c.ExpiresAt = int64(exp) 497 case int64: 498 c.ExpiresAt = exp 499 case json.Number: 500 i, _ := exp.Int64() 501 c.ExpiresAt = i 502 default: 503 return errors.ErrInvalidClaimExpiresAt.WithArgs(v) 504 } 505 mkv[k] = c.ExpiresAt 506 return nil 507 } 508 509 func (c *Claims) unpackID(k string, v interface{}, mkv, tkv map[string]interface{}) error { 510 switch v.(type) { 511 case string: 512 c.ID = v.(string) 513 default: 514 return errors.ErrInvalidIDClaimType.WithArgs(v) 515 } 516 tkv[k] = c.ID 517 mkv[k] = c.ID 518 return nil 519 } 520 521 func (c *Claims) unpackIssuedAt(k string, v interface{}, mkv map[string]interface{}) error { 522 switch exp := v.(type) { 523 case float64: 524 c.IssuedAt = int64(exp) 525 case int: 526 c.IssuedAt = int64(exp) 527 case int64: 528 c.IssuedAt = exp 529 case json.Number: 530 i, _ := exp.Int64() 531 c.IssuedAt = i 532 default: 533 return errors.ErrInvalidClaimIssuedAt.WithArgs(v) 534 } 535 mkv[k] = c.IssuedAt 536 return nil 537 } 538 539 func (c *Claims) unpackIssuer(k string, v interface{}, mkv, tkv map[string]interface{}) error { 540 switch v.(type) { 541 case string: 542 c.Issuer = v.(string) 543 default: 544 return errors.ErrInvalidIssuerClaimType.WithArgs(v) 545 } 546 tkv[k] = c.Issuer 547 mkv[k] = c.Issuer 548 return nil 549 } 550 551 func (c *Claims) unpackNotBefore(k string, v interface{}, mkv map[string]interface{}) error { 552 switch exp := v.(type) { 553 case float64: 554 c.NotBefore = int64(exp) 555 case int: 556 c.NotBefore = int64(exp) 557 case int64: 558 c.NotBefore = exp 559 case json.Number: 560 i, _ := exp.Int64() 561 c.NotBefore = i 562 default: 563 return errors.ErrInvalidClaimNotBefore.WithArgs(v) 564 } 565 mkv[k] = c.NotBefore 566 return nil 567 } 568 569 func (c *Claims) unpackSubject(k string, v interface{}, mkv, tkv map[string]interface{}) error { 570 switch v.(type) { 571 case string: 572 c.Subject = v.(string) 573 default: 574 return errors.ErrInvalidSubjectClaimType.WithArgs(v) 575 } 576 tkv[k] = c.Subject 577 mkv[k] = c.Subject 578 return nil 579 } 580 581 func (c *Claims) unpackMail(k string, v interface{}, mkv, tkv map[string]interface{}) error { 582 switch v.(type) { 583 case string: 584 c.Email = v.(string) 585 default: 586 return errors.ErrInvalidEmailClaimType.WithArgs(k, v) 587 } 588 tkv["email"] = c.Email 589 mkv["email"] = c.Email 590 return nil 591 } 592 593 func (c *Claims) unpackName(k string, v interface{}, mkv, tkv map[string]interface{}) error { 594 switch names := v.(type) { 595 case string: 596 c.Name = names 597 case []interface{}: 598 packedNames := []string{} 599 for _, n := range names { 600 switch n.(type) { 601 case string: 602 packedNames = append(packedNames, n.(string)) 603 default: 604 return errors.ErrInvalidNameClaimType.WithArgs(v) 605 } 606 } 607 c.Name = strings.Join(packedNames, " ") 608 default: 609 return errors.ErrInvalidNameClaimType.WithArgs(v) 610 } 611 tkv[k] = c.Name 612 mkv[k] = c.Name 613 return nil 614 } 615 616 func (c *Claims) unpackRoles(v interface{}) error { 617 switch roles := v.(type) { 618 case []interface{}: 619 for _, role := range roles { 620 switch role.(type) { 621 case string: 622 c.Roles = append(c.Roles, role.(string)) 623 default: 624 return errors.ErrInvalidRole.WithArgs(role) 625 } 626 } 627 case []string: 628 for _, role := range roles { 629 c.Roles = append(c.Roles, role) 630 } 631 case string: 632 for _, role := range strings.Split(roles, " ") { 633 c.Roles = append(c.Roles, role) 634 } 635 default: 636 return errors.ErrInvalidRoleType.WithArgs(v) 637 } 638 return nil 639 } 640 641 func (c *Claims) unpackScopes(k string, v interface{}, mkv, tkv map[string]interface{}) error { 642 switch scopes := v.(type) { 643 case []interface{}: 644 for _, scope := range scopes { 645 switch scope.(type) { 646 case string: 647 c.Scopes = append(c.Scopes, scope.(string)) 648 default: 649 return errors.ErrInvalidScope.WithArgs(scope) 650 } 651 } 652 case []string: 653 for _, scope := range scopes { 654 c.Scopes = append(c.Scopes, scope) 655 } 656 case string: 657 for _, scope := range strings.Split(scopes, " ") { 658 c.Scopes = append(c.Scopes, scope) 659 } 660 default: 661 return errors.ErrInvalidScopeType.WithArgs(v) 662 } 663 tkv["scopes"] = c.Scopes 664 mkv["scopes"] = strings.Join(c.Scopes, " ") 665 return nil 666 } 667 668 func (c *Claims) unpackOrg(k string, v interface{}, mkv, tkv map[string]interface{}) error { 669 switch orgs := v.(type) { 670 case []interface{}: 671 for _, org := range orgs { 672 switch org.(type) { 673 case string: 674 c.Organizations = append(c.Organizations, org.(string)) 675 default: 676 return errors.ErrInvalidOrg.WithArgs(org) 677 } 678 } 679 case []string: 680 for _, org := range orgs { 681 c.Organizations = append(c.Organizations, org) 682 } 683 case string: 684 for _, org := range strings.Split(orgs, " ") { 685 c.Organizations = append(c.Organizations, org) 686 } 687 default: 688 return errors.ErrInvalidOrgType.WithArgs(v) 689 } 690 tkv[k] = c.Organizations 691 mkv[k] = strings.Join(c.Organizations, " ") 692 return nil 693 } 694 695 func (c *Claims) unpackAddr(k string, v interface{}, mkv, tkv map[string]interface{}) error { 696 switch v.(type) { 697 case string: 698 c.Address = v.(string) 699 default: 700 return errors.ErrInvalidAddrType.WithArgs(v) 701 } 702 tkv[k] = c.Address 703 mkv[k] = c.Address 704 return nil 705 } 706 707 func (c *Claims) unpackOrigin(k string, v interface{}, mkv, tkv map[string]interface{}) error { 708 switch v.(type) { 709 case string: 710 c.Origin = v.(string) 711 default: 712 return errors.ErrInvalidOriginClaimType.WithArgs(v) 713 } 714 tkv[k] = c.Origin 715 mkv[k] = c.Origin 716 return nil 717 } 718 719 func (c *Claims) unpackPicture(k string, v interface{}, mkv, tkv map[string]interface{}) error { 720 switch v.(type) { 721 case string: 722 c.PictureURL = v.(string) 723 default: 724 return errors.ErrInvalidPictureClaimType.WithArgs(v) 725 } 726 mkv[k] = c.PictureURL 727 return nil 728 } 729 730 func (c *Claims) unpackAppMetadata(v interface{}) error { 731 switch v.(type) { 732 case map[string]interface{}: 733 appMetadata := v.(map[string]interface{}) 734 if _, authzExists := appMetadata["authorization"]; authzExists { 735 switch appMetadata["authorization"].(type) { 736 case map[string]interface{}: 737 appMetadataAuthz := appMetadata["authorization"].(map[string]interface{}) 738 if _, rolesExists := appMetadataAuthz["roles"]; rolesExists { 739 switch roles := appMetadataAuthz["roles"].(type) { 740 case []interface{}: 741 for _, role := range roles { 742 switch role.(type) { 743 case string: 744 c.Roles = append(c.Roles, role.(string)) 745 default: 746 return errors.ErrInvalidRole.WithArgs(role) 747 } 748 } 749 case []string: 750 for _, role := range roles { 751 c.Roles = append(c.Roles, role) 752 } 753 default: 754 return errors.ErrInvalidAppMetadataRoleType.WithArgs(appMetadataAuthz["roles"]) 755 } 756 } 757 } 758 } 759 } 760 return nil 761 } 762 763 func (c *Claims) unpackRealmAccess(v interface{}) error { 764 switch v.(type) { 765 case map[string]interface{}: 766 realmAccess := v.(map[string]interface{}) 767 if _, rolesExists := realmAccess["roles"]; rolesExists { 768 switch roles := realmAccess["roles"].(type) { 769 case []interface{}: 770 for _, role := range roles { 771 switch role.(type) { 772 case string: 773 c.Roles = append(c.Roles, role.(string)) 774 default: 775 return errors.ErrInvalidRole.WithArgs(role) 776 } 777 } 778 case []string: 779 for _, role := range roles { 780 c.Roles = append(c.Roles, role) 781 } 782 } 783 } 784 } 785 return nil 786 } 787 788 func (c *Claims) unpackAccessListPaths(v interface{}) error { 789 switch v.(type) { 790 case []interface{}: 791 paths := v.([]interface{}) 792 for _, path := range paths { 793 switch path.(type) { 794 case string: 795 if c.AccessList == nil { 796 c.AccessList = &AccessListClaim{} 797 } 798 if c.AccessList.Paths == nil { 799 c.AccessList.Paths = make(map[string]interface{}) 800 } 801 c.AccessList.Paths[path.(string)] = make(map[string]interface{}) 802 default: 803 return errors.ErrInvalidAccessListPath.WithArgs(path) 804 } 805 } 806 } 807 return nil 808 } 809 810 func (c *Claims) unpackAccessList(v interface{}) error { 811 switch v.(type) { 812 case map[string]interface{}: 813 acl := v.(map[string]interface{}) 814 if _, pathsExists := acl["paths"]; pathsExists { 815 switch acl["paths"].(type) { 816 case map[string]interface{}: 817 paths := acl["paths"].(map[string]interface{}) 818 for path := range paths { 819 if c.AccessList == nil { 820 c.AccessList = &AccessListClaim{} 821 } 822 if c.AccessList.Paths == nil { 823 c.AccessList.Paths = make(map[string]interface{}) 824 } 825 c.AccessList.Paths[path] = make(map[string]interface{}) 826 } 827 case []interface{}: 828 paths := acl["paths"].([]interface{}) 829 for _, path := range paths { 830 switch path.(type) { 831 case string: 832 if c.AccessList == nil { 833 c.AccessList = &AccessListClaim{} 834 } 835 if c.AccessList.Paths == nil { 836 c.AccessList.Paths = make(map[string]interface{}) 837 } 838 c.AccessList.Paths[path.(string)] = make(map[string]interface{}) 839 default: 840 return errors.ErrInvalidAccessListPath.WithArgs(path) 841 } 842 } 843 } 844 } 845 } 846 return nil 847 } 848 849 func (c *Claims) unpackMetadata(k string, v interface{}, mkv, tkv map[string]interface{}) error { 850 switch v.(type) { 851 case map[string]interface{}: 852 c.Metadata = v.(map[string]interface{}) 853 default: 854 return errors.ErrInvalidMetadataClaimType.WithArgs(v) 855 } 856 mkv[k] = c.Metadata 857 return nil 858 } 859 860 // NewUser returns a user with associated standard and custom claims. 861 func NewUser(data interface{}) (*User, error) { 862 u := &User{} 863 m, unpackErr := unpackUserData(data) 864 if unpackErr != nil { 865 return nil, unpackErr 866 } 867 c := &Claims{} 868 mkv := make(map[string]interface{}) 869 tkv := make(map[string]interface{}) 870 871 for k, v := range m { 872 switch k { 873 case "aud": 874 if err := c.unpackAudience(k, v, mkv, tkv); err != nil { 875 return nil, err 876 } 877 case "exp": 878 if err := c.unpackExpiresAt(k, v, mkv); err != nil { 879 return nil, err 880 } 881 case "jti": 882 if err := c.unpackID(k, v, mkv, tkv); err != nil { 883 return nil, err 884 } 885 case "iat": 886 if err := c.unpackIssuedAt(k, v, mkv); err != nil { 887 return nil, err 888 } 889 case "iss": 890 if err := c.unpackIssuer(k, v, mkv, tkv); err != nil { 891 return nil, err 892 } 893 case "nbf": 894 if err := c.unpackNotBefore(k, v, mkv); err != nil { 895 return nil, err 896 } 897 case "sub": 898 if err := c.unpackSubject(k, v, mkv, tkv); err != nil { 899 return nil, err 900 } 901 case "email", "mail": 902 if err := c.unpackMail(k, v, mkv, tkv); err != nil { 903 return nil, err 904 } 905 case "name": 906 if err := c.unpackName(k, v, mkv, tkv); err != nil { 907 return nil, err 908 } 909 case "roles", "role", "groups", "group": 910 if err := c.unpackRoles(v); err != nil { 911 return nil, err 912 } 913 case "scopes", "scope": 914 if err := c.unpackScopes(k, v, mkv, tkv); err != nil { 915 return nil, err 916 } 917 case "org": 918 if err := c.unpackOrg(k, v, mkv, tkv); err != nil { 919 return nil, err 920 } 921 case "addr": 922 if err := c.unpackAddr(k, v, mkv, tkv); err != nil { 923 return nil, err 924 } 925 case "origin": 926 if err := c.unpackOrigin(k, v, mkv, tkv); err != nil { 927 return nil, err 928 } 929 case "picture": 930 if err := c.unpackPicture(k, v, mkv, tkv); err != nil { 931 return nil, err 932 } 933 case "app_metadata": 934 if err := c.unpackAppMetadata(v); err != nil { 935 return nil, err 936 } 937 case "realm_access": 938 if err := c.unpackRealmAccess(v); err != nil { 939 return nil, err 940 } 941 case "paths": 942 if err := c.unpackAccessListPaths(v); err != nil { 943 return nil, err 944 } 945 case "acl": 946 if err := c.unpackAccessList(v); err != nil { 947 return nil, err 948 } 949 case "metadata": 950 if err := c.unpackMetadata(k, v, mkv, tkv); err != nil { 951 return nil, err 952 } 953 case "frontend_links", "challenges": 954 default: 955 if c.custom == nil { 956 c.custom = make(map[string]interface{}) 957 } 958 c.custom[k] = v 959 mkv[k] = v 960 } 961 } 962 963 if c.AccessList != nil && c.AccessList.Paths != nil { 964 tkv["acl"] = map[string]interface{}{ 965 "paths": c.AccessList.Paths, 966 } 967 mkv["acl"] = map[string]interface{}{ 968 "paths": c.AccessList.Paths, 969 } 970 } 971 972 if len(c.Roles) == 0 { 973 c.Roles = append(c.Roles, "anonymous") 974 c.Roles = append(c.Roles, "guest") 975 } 976 977 if (len(c.Email) > 0) && (len(c.Name) > 0) { 978 if strings.Contains(c.Name, c.Email) { 979 c.Name = strings.TrimSpace(strings.ReplaceAll(c.Name, c.Email, "")) 980 tkv["name"] = c.Name 981 mkv["name"] = c.Name 982 } 983 } 984 985 if len(c.Roles) > 0 { 986 tkv["roles"] = c.Roles 987 mkv["roles"] = c.Roles 988 } 989 990 u.rkv = make(map[string]interface{}) 991 for _, roleName := range c.Roles { 992 u.rkv[roleName] = true 993 } 994 995 u.Claims = c 996 u.mkv = mkv 997 u.tkv = tkv 998 return u, nil 999 }