github.com/nats-io/jwt/v2@v2.5.6/decoder.go (about)

     1  /*
     2   * Copyright 2020-2022 The NATS Authors
     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  
    16  package jwt
    17  
    18  import (
    19  	"encoding/json"
    20  	"errors"
    21  	"fmt"
    22  	"strings"
    23  
    24  	"github.com/nats-io/nkeys"
    25  )
    26  
    27  const libVersion = 2
    28  
    29  type identifier struct {
    30  	Type          ClaimType `json:"type,omitempty"`
    31  	GenericFields `json:"nats,omitempty"`
    32  }
    33  
    34  func (i *identifier) Kind() ClaimType {
    35  	if i.Type != "" {
    36  		return i.Type
    37  	}
    38  	return i.GenericFields.Type
    39  }
    40  
    41  func (i *identifier) Version() int {
    42  	if i.Type != "" {
    43  		return 1
    44  	}
    45  	return i.GenericFields.Version
    46  }
    47  
    48  type v1ClaimsDataDeletedFields struct {
    49  	Tags          TagList   `json:"tags,omitempty"`
    50  	Type          ClaimType `json:"type,omitempty"`
    51  	IssuerAccount string    `json:"issuer_account,omitempty"`
    52  }
    53  
    54  // Decode takes a JWT string decodes it and validates it
    55  // and return the embedded Claims. If the token header
    56  // doesn't match the expected algorithm, or the claim is
    57  // not valid or verification fails an error is returned.
    58  func Decode(token string) (Claims, error) {
    59  	// must have 3 chunks
    60  	chunks := strings.Split(token, ".")
    61  	if len(chunks) != 3 {
    62  		return nil, errors.New("expected 3 chunks")
    63  	}
    64  
    65  	// header
    66  	if _, err := parseHeaders(chunks[0]); err != nil {
    67  		return nil, err
    68  	}
    69  	// claim
    70  	data, err := decodeString(chunks[1])
    71  	if err != nil {
    72  		return nil, err
    73  	}
    74  	ver, claim, err := loadClaims(data)
    75  	if err != nil {
    76  		return nil, err
    77  	}
    78  
    79  	// sig
    80  	sig, err := decodeString(chunks[2])
    81  	if err != nil {
    82  		return nil, err
    83  	}
    84  
    85  	if ver <= 1 {
    86  		if !claim.verify(chunks[1], sig) {
    87  			return nil, errors.New("claim failed V1 signature verification")
    88  		}
    89  	} else {
    90  		if !claim.verify(token[:len(chunks[0])+len(chunks[1])+1], sig) {
    91  			return nil, errors.New("claim failed V2 signature verification")
    92  		}
    93  	}
    94  
    95  	prefixes := claim.ExpectedPrefixes()
    96  	if prefixes != nil {
    97  		ok := false
    98  		issuer := claim.Claims().Issuer
    99  		for _, p := range prefixes {
   100  			switch p {
   101  			case nkeys.PrefixByteAccount:
   102  				if nkeys.IsValidPublicAccountKey(issuer) {
   103  					ok = true
   104  				}
   105  			case nkeys.PrefixByteOperator:
   106  				if nkeys.IsValidPublicOperatorKey(issuer) {
   107  					ok = true
   108  				}
   109  			case nkeys.PrefixByteUser:
   110  				if nkeys.IsValidPublicUserKey(issuer) {
   111  					ok = true
   112  				}
   113  			case nkeys.PrefixByteServer:
   114  				if nkeys.IsValidPublicServerKey(issuer) {
   115  					ok = true
   116  				}
   117  			}
   118  		}
   119  		if !ok {
   120  			return nil, fmt.Errorf("unable to validate expected prefixes - %v", prefixes)
   121  		}
   122  	}
   123  	return claim, nil
   124  }
   125  
   126  func loadClaims(data []byte) (int, Claims, error) {
   127  	var id identifier
   128  	if err := json.Unmarshal(data, &id); err != nil {
   129  		return -1, nil, err
   130  	}
   131  
   132  	if id.Version() > libVersion {
   133  		return -1, nil, errors.New("JWT was generated by a newer version ")
   134  	}
   135  
   136  	var claim Claims
   137  	var err error
   138  	switch id.Kind() {
   139  	case OperatorClaim:
   140  		claim, err = loadOperator(data, id.Version())
   141  	case AccountClaim:
   142  		claim, err = loadAccount(data, id.Version())
   143  	case UserClaim:
   144  		claim, err = loadUser(data, id.Version())
   145  	case ActivationClaim:
   146  		claim, err = loadActivation(data, id.Version())
   147  	case AuthorizationRequestClaim:
   148  		claim, err = loadAuthorizationRequest(data, id.Version())
   149  	case AuthorizationResponseClaim:
   150  		claim, err = loadAuthorizationResponse(data, id.Version())
   151  	case "cluster":
   152  		return -1, nil, errors.New("ClusterClaims are not supported")
   153  	case "server":
   154  		return -1, nil, errors.New("ServerClaims are not supported")
   155  	default:
   156  		var gc GenericClaims
   157  		if err := json.Unmarshal(data, &gc); err != nil {
   158  			return -1, nil, err
   159  		}
   160  		return -1, &gc, nil
   161  	}
   162  
   163  	return id.Version(), claim, err
   164  }