Skip to content

Instantly share code, notes, and snippets.

@lsmag
Created April 14, 2014 19:57
Show Gist options
  • Save lsmag/10678251 to your computer and use it in GitHub Desktop.
Save lsmag/10678251 to your computer and use it in GitHub Desktop.
{
"metadata": {
"name": ""
},
"nbformat": 3,
"nbformat_minor": 0,
"worksheets": [
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Como usar JWKEST para assinar e verificar id_token's usando RS256"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"import Crypto.PublicKey.RSA as RSA"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 1
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from jwkest.jwk import RSAKey"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 2
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from jwkest.jws import JWS"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 3
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Para criar um id_token usando RS256 (RSA) \u00e9 preciso um par de chaves RSA (que ser\u00e3o geradas aqui)."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"key = RSA.generate(2048)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 5
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"priv_pem = key.exportKey()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 6
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"pub_pem = key.publickey().exportKey()"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 8
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"priv_key = RSA.importKey(priv_pem)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 9
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"pub_key = RSA.importKey(pub_pem)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 10
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Uma vez criadas as chaves p\u00fablica e privada, podemos criar um id_token e ent\u00e3o assin\u00e1-lo"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"payload = {\n",
" 'iss': 'https://example.it',\n",
" 'sub': '123456',\n",
" 'aud': 'https://consumer.it',\n",
" }"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 11
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"id_token = JWS(payload, alg='RS256')"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 12
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"id_token.sign_compact([RSAKey(key=priv_key)])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 13,
"text": [
"'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuaXQiLCJzdWIiOiIxMjM0NTYiLCJhdWQiOiJodHRwczovL2NvbnN1bWVyLml0In0.idPbDOKzfG3cKDikoW76tPVIA7_PY_Ni885VnswelFTGp2BxA0oiunOKVqqrIzs23wbvEgT2blJr7n2G0MDg8Z1DnMlbmL49-bnazHcZfFvC2XGqBGlxEm2rU7ylFiPX5y7qroEk0ErqVI5sLyLEfWBsv2UQ0VkF6pU_01TJ9LUmGcm0lnpYNUO0lpx3sz1cTSJP4rjlPICR6uOLpbcvTCWGwbmEikTIjlDsJm-rou91gWNMBBFkFOcxMG6W5mdqlN5Y3J8zjJV5YzoZt7vz4r3hr60eNPbJAbsW0HSlfsfSgF5ed9P85Y43j0AHLlUJI_ORFxxw_u_DLglE1YTj5A'"
]
}
],
"prompt_number": 13
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Apenas pra revisar, vamos checar cada parte do token:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from base64 import b64decode"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 14
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"b64decode('eyJhbGciOiJSUzI1NiJ9')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 15,
"text": [
"'{\"alg\":\"RS256\"}'"
]
}
],
"prompt_number": 15
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"\n",
"# Sinais de \"=\" adicionados no final pois o texto encriptado em b64 deve ser m\u00faltiplo de 4\n",
"b64decode('eyJpc3MiOiJodHRwczovL2V4YW1wbGUuaXQiLCJzdWIiOiIxMjM0NTYiLCJhdWQiOiJodHRwczovL2NvbnN1bWVyLml0In0===')"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 19,
"text": [
"'{\"iss\":\"https://example.it\",\"sub\":\"123456\",\"aud\":\"https://consumer.it\"}'"
]
}
],
"prompt_number": 19
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Agora, vamos tentar VERIFICAR o token usando a pub_key criada"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"unverified_token = 'eyJhbGciOiJSUzI1NiJ9.eyJpc3MiOiJodHRwczovL2V4YW1wbGUuaXQiLCJzdWIiOiIxMjM0NTYiLCJhdWQiOiJodHRwczovL2NvbnN1bWVyLml0In0.idPbDOKzfG3cKDikoW76tPVIA7_PY_Ni885VnswelFTGp2BxA0oiunOKVqqrIzs23wbvEgT2blJr7n2G0MDg8Z1DnMlbmL49-bnazHcZfFvC2XGqBGlxEm2rU7ylFiPX5y7qroEk0ErqVI5sLyLEfWBsv2UQ0VkF6pU_01TJ9LUmGcm0lnpYNUO0lpx3sz1cTSJP4rjlPICR6uOLpbcvTCWGwbmEikTIjlDsJm-rou91gWNMBBFkFOcxMG6W5mdqlN5Y3J8zjJV5YzoZt7vz4r3hr60eNPbJAbsW0HSlfsfSgF5ed9P85Y43j0AHLlUJI_ORFxxw_u_DLglE1YTj5A'"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 20
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"JWS().verify_compact(unverified_token, [RSAKey(key=pub_key)])"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 21,
"text": [
"'{\"iss\":\"https://example.it\",\"sub\":\"123456\",\"aud\":\"https://consumer.it\"}'"
]
}
],
"prompt_number": 21
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Finally!\n",
"\n",
"Agora precisamos expor a pubkey criada como uma JWK, para ser acessada pelo RP."
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"RSAKey(key=pub_key).to_dict()"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 24,
"text": [
"{'e': 'AQAB',\n",
" 'kty': 'RSA',\n",
" 'n': 'wqAXbMWD-onBqLwjsdafB32tVwQNJRx7NyucrwsjzSlOJYlmlhxwruMN9TrpeTqTvmtRfO71UWRzrfdKJaCVooHcYHE3UytK0S7RcnE1zi59I-7c2p8h2CrF9iBXDnhImbfpNv8BWRJn7vjzv11B6xF5ma2BrgwUux2ah9-xxMJG8wgDWt3lx_dDSIR4T5Ack4ta0PXgDT_jNIV0p-TOqOvz1UlCGV7x3uf446RyqxVuCYM980kA7c0WaD67r0lTfomXZs9WGH-ZbvF1UHlVzncj_M6EZ1SpcutDR_L3z0J2bSPEYrGx6nhKysF9JhyXAtcA9UqPg-onOUmkb0gUCQ'}"
]
}
],
"prompt_number": 24
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"**E \u00e9 isso** que precisaremos expor no jwks_uri =D\n",
"\n",
"Uma vez exportado para o formato JWK e exposto no endpoint correto, \u00e9 poss\u00edvel carregar a chave p\u00fablica para uso facilmente atrav\u00e9s da seguinte fun\u00e7\u00e3o:"
]
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"from jwkest.jwk import load_jwks_from_url"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 25
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"# Por exemplo,\n",
"loaded_keys = load_jwks_from_url('https://connect-op.heroku.com/jwks.json')\n",
"# na hora de usar: JWS().verify_compact(some_token, loaded_keys)"
],
"language": "python",
"metadata": {},
"outputs": [],
"prompt_number": 27
},
{
"cell_type": "code",
"collapsed": false,
"input": [
"loaded_keys"
],
"language": "python",
"metadata": {},
"outputs": [
{
"metadata": {},
"output_type": "pyout",
"prompt_number": 28,
"text": [
"[<jwkest.jwk.RSAKey instance at 0x25ebfc8>]"
]
}
],
"prompt_number": 28
},
{
"cell_type": "code",
"collapsed": false,
"input": [],
"language": "python",
"metadata": {},
"outputs": []
}
],
"metadata": {}
}
]
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment