...

Source file src/github.com/ory/fosite/token/jwt/map_claims.go

Documentation: github.com/ory/fosite/token/jwt

     1  package jwt
     2  
     3  import (
     4  	"bytes"
     5  	"crypto/subtle"
     6  	"encoding/json"
     7  	"errors"
     8  	"time"
     9  
    10  	"github.com/ory/x/errorsx"
    11  	jjson "gopkg.in/square/go-jose.v2/json"
    12  )
    13  
    14  var TimeFunc = time.Now
    15  
    16  // MapClaims provides backwards compatible validations not available in `go-jose`.
    17  // It was taken from [here](https://raw.githubusercontent.com/form3tech-oss/jwt-go/master/map_claims.go).
    18  //
    19  // Claims type that uses the map[string]interface{} for JSON decoding
    20  // This is the default claims type if you don't supply one
    21  type MapClaims map[string]interface{}
    22  
    23  // Compares the aud claim against cmp.
    24  // If required is false, this method will return true if the value matches or is unset
    25  func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
    26  	var aud []string
    27  	switch v := m["aud"].(type) {
    28  	case []string:
    29  		aud = v
    30  	case []interface{}:
    31  		for _, a := range v {
    32  			vs, ok := a.(string)
    33  			if !ok {
    34  				return false
    35  			}
    36  			aud = append(aud, vs)
    37  		}
    38  	case string:
    39  		aud = append(aud, v)
    40  	default:
    41  		return false
    42  	}
    43  	return verifyAud(aud, cmp, req)
    44  }
    45  
    46  // Compares the exp claim against cmp.
    47  // If required is false, this method will return true if the value matches or is unset
    48  func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
    49  	if v, ok := m.toInt64("exp"); ok {
    50  		return verifyExp(v, cmp, req)
    51  	}
    52  	return !req
    53  }
    54  
    55  // Compares the iat claim against cmp.
    56  // If required is false, this method will return true if the value matches or is unset
    57  func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
    58  	if v, ok := m.toInt64("iat"); ok {
    59  		return verifyIat(v, cmp, req)
    60  	}
    61  	return !req
    62  }
    63  
    64  // Compares the iss claim against cmp.
    65  // If required is false, this method will return true if the value matches or is unset
    66  func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
    67  	iss, _ := m["iss"].(string)
    68  	return verifyIss(iss, cmp, req)
    69  }
    70  
    71  // Compares the nbf claim against cmp.
    72  // If required is false, this method will return true if the value matches or is unset
    73  func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
    74  	if v, ok := m.toInt64("nbf"); ok {
    75  		return verifyNbf(v, cmp, req)
    76  	}
    77  
    78  	return !req
    79  }
    80  
    81  func (m MapClaims) toInt64(claim string) (int64, bool) {
    82  	switch t := m[claim].(type) {
    83  	case float64:
    84  		return int64(t), true
    85  	case int64:
    86  		return t, true
    87  	case json.Number:
    88  		v, err := t.Int64()
    89  		if err == nil {
    90  			return v, true
    91  		}
    92  		vf, err := t.Float64()
    93  		if err != nil {
    94  			return 0, false
    95  		}
    96  
    97  		return int64(vf), true
    98  	}
    99  	return 0, false
   100  }
   101  
   102  // Validates time based claims "exp, iat, nbf".
   103  // There is no accounting for clock skew.
   104  // As well, if any of the above claims are not in the token, it will still
   105  // be considered a valid claim.
   106  func (m MapClaims) Valid() error {
   107  	vErr := new(ValidationError)
   108  	now := TimeFunc().Unix()
   109  
   110  	if !m.VerifyExpiresAt(now, false) {
   111  		vErr.Inner = errors.New("Token is expired")
   112  		vErr.Errors |= ValidationErrorExpired
   113  	}
   114  
   115  	if !m.VerifyIssuedAt(now, false) {
   116  		vErr.Inner = errors.New("Token used before issued")
   117  		vErr.Errors |= ValidationErrorIssuedAt
   118  	}
   119  
   120  	if !m.VerifyNotBefore(now, false) {
   121  		vErr.Inner = errors.New("Token is not valid yet")
   122  		vErr.Errors |= ValidationErrorNotValidYet
   123  	}
   124  
   125  	if vErr.valid() {
   126  		return nil
   127  	}
   128  
   129  	return vErr
   130  }
   131  
   132  func (m MapClaims) UnmarshalJSON(b []byte) error {
   133  	// This custom unmarshal allows to configure the
   134  	// go-jose decoding settings since there is no other way
   135  	// see https://github.com/square/go-jose/issues/353.
   136  	// If issue is closed with a better solution
   137  	// this custom Unmarshal method can be removed
   138  	d := jjson.NewDecoder(bytes.NewReader(b))
   139  	mp := map[string]interface{}(m)
   140  	d.SetNumberType(jjson.UnmarshalIntOrFloat)
   141  	if err := d.Decode(&mp); err != nil {
   142  		return errorsx.WithStack(err)
   143  	}
   144  
   145  	return nil
   146  }
   147  
   148  func verifyAud(aud []string, cmp string, required bool) bool {
   149  	if len(aud) == 0 {
   150  		return !required
   151  	}
   152  
   153  	for _, a := range aud {
   154  		if subtle.ConstantTimeCompare([]byte(a), []byte(cmp)) != 0 {
   155  			return true
   156  		}
   157  	}
   158  	return false
   159  }
   160  
   161  func verifyExp(exp int64, now int64, required bool) bool {
   162  	if exp == 0 {
   163  		return !required
   164  	}
   165  	return now <= exp
   166  }
   167  
   168  func verifyIat(iat int64, now int64, required bool) bool {
   169  	if iat == 0 {
   170  		return !required
   171  	}
   172  	return now >= iat
   173  }
   174  
   175  func verifyIss(iss string, cmp string, required bool) bool {
   176  	if iss == "" {
   177  		return !required
   178  	}
   179  	if subtle.ConstantTimeCompare([]byte(iss), []byte(cmp)) != 0 {
   180  		return true
   181  	} else {
   182  		return false
   183  	}
   184  }
   185  
   186  func verifyNbf(nbf int64, now int64, required bool) bool {
   187  	if nbf == 0 {
   188  		return !required
   189  	}
   190  	return now >= nbf
   191  }
   192  

View as plain text