github.com/aarzilli/tools@v0.0.0-20151123112009-0d27094f75e0/appengine/login/googlesignin/jwt-go/jwt.go (about)

     1  package jwt
     2  
     3  import (
     4  	"encoding/base64"
     5  	"encoding/json"
     6  	"net/http"
     7  	"strings"
     8  	"time"
     9  )
    10  
    11  // TimeFunc provides the current time when parsing token to validate "exp" claim (expiration time).
    12  // You can override it to use another time value.  This is useful for testing or if your
    13  // server uses a different time zone than your tokens.
    14  var TimeFunc = time.Now
    15  
    16  // Parse methods use this callback function to supply
    17  // the key for verification.  The function receives the parsed,
    18  // but unverified Token.  This allows you to use propries in the
    19  // Header of the token (such as `kid`) to identify which key to use.
    20  type Keyfunc func(*Token) (interface{}, error)
    21  
    22  // A JWT Token.  Different fields will be used depending on whether you're
    23  // creating or parsing/verifying a token.
    24  type Token struct {
    25  	Raw       string                 // The raw token.  Populated when you Parse a token
    26  	Method    SigningMethod          // The signing method used or to be used
    27  	Header    map[string]interface{} // The first segment of the token
    28  	Claims    map[string]interface{} // The second segment of the token
    29  	Signature string                 // The third segment of the token.  Populated when you Parse a token
    30  	Valid     bool                   // Is the token valid?  Populated when you Parse/Verify a token
    31  }
    32  
    33  // Create a new Token.  Takes a signing method
    34  func New(method SigningMethod) *Token {
    35  	return &Token{
    36  		Header: map[string]interface{}{
    37  			"typ": "JWT",
    38  			"alg": method.Alg(),
    39  		},
    40  		Claims: make(map[string]interface{}),
    41  		Method: method,
    42  	}
    43  }
    44  
    45  // Get the complete, signed token
    46  func (t *Token) SignedString(key interface{}) (string, error) {
    47  	var sig, sstr string
    48  	var err error
    49  	if sstr, err = t.SigningString(); err != nil {
    50  		return "", err
    51  	}
    52  	if sig, err = t.Method.Sign(sstr, key); err != nil {
    53  		return "", err
    54  	}
    55  	return strings.Join([]string{sstr, sig}, "."), nil
    56  }
    57  
    58  // Generate the signing string.  This is the
    59  // most expensive part of the whole deal.  Unless you
    60  // need this for something special, just go straight for
    61  // the SignedString.
    62  func (t *Token) SigningString() (string, error) {
    63  	var err error
    64  	parts := make([]string, 2)
    65  	for i, _ := range parts {
    66  		var source map[string]interface{}
    67  		if i == 0 {
    68  			source = t.Header
    69  		} else {
    70  			source = t.Claims
    71  		}
    72  
    73  		var jsonValue []byte
    74  		if jsonValue, err = json.Marshal(source); err != nil {
    75  			return "", err
    76  		}
    77  
    78  		parts[i] = EncodeSegment(jsonValue)
    79  	}
    80  	return strings.Join(parts, "."), nil
    81  }
    82  
    83  // Parse, validate, and return a token.
    84  // keyFunc will receive the parsed token and should return the key for validating.
    85  // If everything is kosher, err will be nil
    86  func Parse(tokenString string, keyFunc Keyfunc) (*Token, error) {
    87  	parts := strings.Split(tokenString, ".")
    88  	if len(parts) != 3 {
    89  		return nil, &ValidationError{err: "token contains an invalid number of segments", Errors: ValidationErrorMalformed}
    90  	}
    91  
    92  	var err error
    93  	token := &Token{Raw: tokenString}
    94  	// parse Header
    95  	var headerBytes []byte
    96  	if headerBytes, err = DecodeSegment(parts[0]); err != nil {
    97  		return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
    98  	}
    99  	if err = json.Unmarshal(headerBytes, &token.Header); err != nil {
   100  		return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
   101  	}
   102  
   103  	// parse Claims
   104  	var claimBytes []byte
   105  	if claimBytes, err = DecodeSegment(parts[1]); err != nil {
   106  		return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
   107  	}
   108  	if err = json.Unmarshal(claimBytes, &token.Claims); err != nil {
   109  		return token, &ValidationError{err: err.Error(), Errors: ValidationErrorMalformed}
   110  	}
   111  
   112  	// Lookup signature method
   113  	if method, ok := token.Header["alg"].(string); ok {
   114  		if token.Method = GetSigningMethod(method); token.Method == nil {
   115  			return token, &ValidationError{err: "signing method (alg) is unavailable.", Errors: ValidationErrorUnverifiable}
   116  		}
   117  	} else {
   118  		return token, &ValidationError{err: "signing method (alg) is unspecified.", Errors: ValidationErrorUnverifiable}
   119  	}
   120  
   121  	// Lookup key
   122  	var key interface{}
   123  	if keyFunc == nil {
   124  		// keyFunc was not provided.  short circuiting validation
   125  		return token, &ValidationError{err: "no Keyfunc was provided.", Errors: ValidationErrorUnverifiable}
   126  	}
   127  	if key, err = keyFunc(token); err != nil {
   128  		// keyFunc returned an error
   129  		return token, &ValidationError{err: err.Error(), Errors: ValidationErrorUnverifiable}
   130  	}
   131  
   132  	// Check expiration times
   133  	vErr := &ValidationError{}
   134  	now := TimeFunc().Unix()
   135  	if exp, ok := token.Claims["exp"].(float64); ok {
   136  		if now > int64(exp) {
   137  			vErr.err = "token is expired"
   138  			vErr.Errors |= ValidationErrorExpired
   139  		}
   140  	}
   141  	if nbf, ok := token.Claims["nbf"].(float64); ok {
   142  		if now < int64(nbf) {
   143  			vErr.err = "token is not valid yet"
   144  			vErr.Errors |= ValidationErrorNotValidYet
   145  		}
   146  	}
   147  
   148  	// Perform validation
   149  	if err = token.Method.Verify(strings.Join(parts[0:2], "."), parts[2], key); err != nil {
   150  		vErr.err = err.Error()
   151  		vErr.Errors |= ValidationErrorSignatureInvalid
   152  	}
   153  
   154  	if vErr.valid() {
   155  		token.Valid = true
   156  		return token, nil
   157  	}
   158  
   159  	return token, vErr
   160  }
   161  
   162  // Try to find the token in an http.Request.
   163  // This method will call ParseMultipartForm if there's no token in the header.
   164  // Currently, it looks in the Authorization header as well as
   165  // looking for an 'access_token' request parameter in req.Form.
   166  func ParseFromRequest(req *http.Request, keyFunc Keyfunc) (token *Token, err error) {
   167  
   168  	// Look for an Authorization header
   169  	if ah := req.Header.Get("Authorization"); ah != "" {
   170  		// Should be a bearer token
   171  		if len(ah) > 6 && strings.ToUpper(ah[0:6]) == "BEARER" {
   172  			return Parse(ah[7:], keyFunc)
   173  		}
   174  	}
   175  
   176  	// Look for "access_token" parameter
   177  	req.ParseMultipartForm(10e6)
   178  	if tokStr := req.Form.Get("access_token"); tokStr != "" {
   179  		return Parse(tokStr, keyFunc)
   180  	}
   181  
   182  	return nil, ErrNoTokenInRequest
   183  
   184  }
   185  
   186  // Encode JWT specific base64url encoding with padding stripped
   187  func EncodeSegment(seg []byte) string {
   188  	return strings.TrimRight(base64.URLEncoding.EncodeToString(seg), "=")
   189  }
   190  
   191  // Decode JWT specific base64url encoding with padding stripped
   192  func DecodeSegment(seg string) ([]byte, error) {
   193  	if l := len(seg) % 4; l > 0 {
   194  		seg += strings.Repeat("=", 4-l)
   195  	}
   196  
   197  	return base64.URLEncoding.DecodeString(seg)
   198  }