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()))