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  }