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