map_claims.go raw

   1  package jwt
   2  
   3  import (
   4  	"encoding/json"
   5  	"errors"
   6  	"time"
   7  	// "fmt"
   8  )
   9  
  10  // MapClaims is a claims type that uses the map[string]interface{} for JSON decoding.
  11  // This is the default claims type if you don't supply one
  12  type MapClaims map[string]interface{}
  13  
  14  // VerifyAudience Compares the aud claim against cmp.
  15  // If required is false, this method will return true if the value matches or is unset
  16  func (m MapClaims) VerifyAudience(cmp string, req bool) bool {
  17  	var aud []string
  18  	switch v := m["aud"].(type) {
  19  	case string:
  20  		aud = append(aud, v)
  21  	case []string:
  22  		aud = v
  23  	case []interface{}:
  24  		for _, a := range v {
  25  			vs, ok := a.(string)
  26  			if !ok {
  27  				return false
  28  			}
  29  			aud = append(aud, vs)
  30  		}
  31  	}
  32  	return verifyAud(aud, cmp, req)
  33  }
  34  
  35  // VerifyExpiresAt compares the exp claim against cmp (cmp <= exp).
  36  // If req is false, it will return true, if exp is unset.
  37  func (m MapClaims) VerifyExpiresAt(cmp int64, req bool) bool {
  38  	cmpTime := time.Unix(cmp, 0)
  39  
  40  	v, ok := m["exp"]
  41  	if !ok {
  42  		return !req
  43  	}
  44  
  45  	switch exp := v.(type) {
  46  	case float64:
  47  		if exp == 0 {
  48  			return verifyExp(nil, cmpTime, req)
  49  		}
  50  
  51  		return verifyExp(&newNumericDateFromSeconds(exp).Time, cmpTime, req)
  52  	case json.Number:
  53  		v, _ := exp.Float64()
  54  
  55  		return verifyExp(&newNumericDateFromSeconds(v).Time, cmpTime, req)
  56  	}
  57  
  58  	return false
  59  }
  60  
  61  // VerifyIssuedAt compares the exp claim against cmp (cmp >= iat).
  62  // If req is false, it will return true, if iat is unset.
  63  func (m MapClaims) VerifyIssuedAt(cmp int64, req bool) bool {
  64  	cmpTime := time.Unix(cmp, 0)
  65  
  66  	v, ok := m["iat"]
  67  	if !ok {
  68  		return !req
  69  	}
  70  
  71  	switch iat := v.(type) {
  72  	case float64:
  73  		if iat == 0 {
  74  			return verifyIat(nil, cmpTime, req)
  75  		}
  76  
  77  		return verifyIat(&newNumericDateFromSeconds(iat).Time, cmpTime, req)
  78  	case json.Number:
  79  		v, _ := iat.Float64()
  80  
  81  		return verifyIat(&newNumericDateFromSeconds(v).Time, cmpTime, req)
  82  	}
  83  
  84  	return false
  85  }
  86  
  87  // VerifyNotBefore compares the nbf claim against cmp (cmp >= nbf).
  88  // If req is false, it will return true, if nbf is unset.
  89  func (m MapClaims) VerifyNotBefore(cmp int64, req bool) bool {
  90  	cmpTime := time.Unix(cmp, 0)
  91  
  92  	v, ok := m["nbf"]
  93  	if !ok {
  94  		return !req
  95  	}
  96  
  97  	switch nbf := v.(type) {
  98  	case float64:
  99  		if nbf == 0 {
 100  			return verifyNbf(nil, cmpTime, req)
 101  		}
 102  
 103  		return verifyNbf(&newNumericDateFromSeconds(nbf).Time, cmpTime, req)
 104  	case json.Number:
 105  		v, _ := nbf.Float64()
 106  
 107  		return verifyNbf(&newNumericDateFromSeconds(v).Time, cmpTime, req)
 108  	}
 109  
 110  	return false
 111  }
 112  
 113  // VerifyIssuer compares the iss claim against cmp.
 114  // If required is false, this method will return true if the value matches or is unset
 115  func (m MapClaims) VerifyIssuer(cmp string, req bool) bool {
 116  	iss, _ := m["iss"].(string)
 117  	return verifyIss(iss, cmp, req)
 118  }
 119  
 120  // Valid validates time based claims "exp, iat, nbf".
 121  // There is no accounting for clock skew.
 122  // As well, if any of the above claims are not in the token, it will still
 123  // be considered a valid claim.
 124  func (m MapClaims) Valid() error {
 125  	vErr := new(ValidationError)
 126  	now := TimeFunc().Unix()
 127  
 128  	if !m.VerifyExpiresAt(now, false) {
 129  		// TODO(oxisto): this should be replaced with ErrTokenExpired
 130  		vErr.Inner = errors.New("Token is expired")
 131  		vErr.Errors |= ValidationErrorExpired
 132  	}
 133  
 134  	if !m.VerifyIssuedAt(now, false) {
 135  		// TODO(oxisto): this should be replaced with ErrTokenUsedBeforeIssued
 136  		vErr.Inner = errors.New("Token used before issued")
 137  		vErr.Errors |= ValidationErrorIssuedAt
 138  	}
 139  
 140  	if !m.VerifyNotBefore(now, false) {
 141  		// TODO(oxisto): this should be replaced with ErrTokenNotValidYet
 142  		vErr.Inner = errors.New("Token is not valid yet")
 143  		vErr.Errors |= ValidationErrorNotValidYet
 144  	}
 145  
 146  	if vErr.valid() {
 147  		return nil
 148  	}
 149  
 150  	return vErr
 151  }
 152