istio.io/istio@v0.0.0-20240520182934-d79c90f27776/security/tools/jwt/samples/gen-jwt.py (about)

     1  #!/usr/bin/python
     2  
     3  # Copyright 2018 Istio Authors
     4  #
     5  # Licensed under the Apache License, Version 2.0 (the "License");
     6  # you may not use this file except in compliance with the License.
     7  # You may obtain a copy of the License at
     8  #
     9  #     http://www.apache.org/licenses/LICENSE-2.0
    10  #
    11  # Unless required by applicable law or agreed to in writing, software
    12  # distributed under the License is distributed on an "AS IS" BASIS,
    13  # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  # See the License for the specific language governing permissions and
    15  # limitations under the License.
    16  
    17  """Python script generates a JWT signed with custom private key.
    18  
    19  Example:
    20  ./gen-jwt.py  --iss example-issuer --aud foo,bar --claims=email:foo@google.com,dead:beef key.pem -listclaim key1 val2 val3 -listclaim key2 val3 val4
    21  """
    22  from __future__ import print_function
    23  import argparse
    24  import copy
    25  import time
    26  
    27  from jwcrypto import jwt, jwk
    28  
    29  
    30  def main(args):
    31      """Generates a signed JSON Web Token from local private key."""
    32      with open(args.key) as f:
    33          pem_data = f.read()
    34      f.closed
    35  
    36      pem_data_encode = pem_data.encode("utf-8")
    37      key = jwk.JWK.from_pem(pem_data_encode)
    38  
    39      if args.jwks:
    40          with open(args.jwks, "w+") as fout:
    41              fout.write("{ \"keys\":[ ")
    42              fout.write(key.export(private_key=False))
    43              fout.write("]}")
    44          fout.close
    45  
    46      now = int(time.time())
    47      payload = {
    48          # expire in one hour.
    49          "exp": now + args.expire,
    50          "iat": now,
    51      }
    52      if args.iss:
    53          payload["iss"] = args.iss
    54      if args.sub:
    55          payload["sub"] = args.sub
    56      else:
    57          payload["sub"] = args.iss
    58  
    59      if args.aud:
    60          if "," in args.aud:
    61              payload["aud"] = args.aud.split(",")
    62          else:
    63              payload["aud"] = args.aud
    64  
    65      if args.claims:
    66          for item in args.claims.split(","):
    67              k, v = item.split(':')
    68              payload[k] = v
    69  
    70      if args.listclaim:
    71          for item in args.listclaim:
    72              if (len(item) > 1):
    73                  k = item[0]
    74                  v = item[1:]
    75                  payload[k] = v
    76  
    77      if args.nestedclaim:
    78          nested = {}
    79          for item in args.nestedclaim:
    80              if (len(item) > 1):
    81                  k = item[0]
    82                  v = item[1:]
    83                  if len(v) == 1:
    84                      v = v[0]
    85                  nested[k] = v
    86          nested["nested-2"] = copy.copy(nested)
    87          payload[args.nestedkey] = nested
    88  
    89      token = jwt.JWT(header={"alg": "RS256", "typ": "JWT", "kid": key.key_id},
    90                      claims=payload)
    91  
    92      token.make_signed_token(key)
    93  
    94      return token.serialize()
    95  
    96  
    97  if __name__ == '__main__':
    98      parser = argparse.ArgumentParser(
    99          description=__doc__,
   100          formatter_class=argparse.RawDescriptionHelpFormatter)
   101      # positional arguments
   102      parser.add_argument(
   103          'key',
   104          help='The path to the key pem file. The key can be generated with openssl command: `openssl genrsa -out key.pem 2048`')
   105      # optional arguments
   106      parser.add_argument("-iss", "--iss",
   107                          default="testing@secure.istio.io",
   108                          help="iss claim. Default is `testing@secure.istio.io`")
   109      parser.add_argument("-aud", "--aud",
   110                          help="aud claim. This is comma-separated-list of audiences")
   111      parser.add_argument("-sub", "--sub",
   112                          help="sub claim. If not provided, it is set to the same as iss claim.")
   113      parser.add_argument("-claims", "--claims",
   114                          help="Other claims in format name1:value1,name2:value2 etc. Only string values are supported.")
   115      parser.add_argument("-jwks", "--jwks",
   116                          help="Path to the output file for JWKS.")
   117      parser.add_argument("-expire", "--expire", type=int, default=3600,
   118                          help="JWT expiration time in second. Default is 1 hour.")
   119      parser.add_argument("-nestedkey", "--nestedkey",
   120                          default="nested",
   121                          help="nested claim key. Only useful when `nestedclaim` is provided. Default is `nested`")
   122      parser.add_argument(
   123          "-listclaim",
   124          "--listclaim",
   125          action='append',
   126          nargs='+',
   127          help="A list claim in format key1 value2 value3... Only string values are supported. Multiple list claims can be specified, e.g., -listclaim key1 val2 val3 -listclaim key2 val3 val4.")
   128      parser.add_argument(
   129          "-nestedclaim",
   130          "--nestedclaim",
   131          action='append',
   132          nargs='+',
   133          help="Nested claim in format key value1 [value2 ...], only string values are supported, will be added under the nested key in the JWT payload. "
   134               "Multiple nested claims can be specified, e.g., -nestedclaim key1 val2 val3 -nestedclaim key2 val3 val4."
   135      )
   136      print(main(parser.parse_args()))