def deserialize(self, jwt, key=None): """Deserialize a JWT token. NOTE: Destroys any current status and tries to import the raw token provided. :param jwt: a 'raw' JWT token. :param key: A (:class:`jwcrypto.jwk.JWK`) verification or decryption key. """ c = jwt.count('.') if c == 2: self.token = JWS() elif c == 4: self.token = JWE() else: raise ValueError("Token format unrecognized") # Apply algs restrictions if any, before performing any operation if self._algs: self.token.allowed_algs = self._algs # now deserialize and also decrypt/verify (or raise) if we # have a key self.token.deserialize(jwt, key) if key is not None: self.header = self.token.jose_header self.claims = self.token.payload.decode('utf-8') self._check_provided_claims()
def decrypt(self, ciphertext): try: jwe = JWE() jwe.deserialize(ciphertext, key=self._private_jwk) plaintext = jwe.payload.decode('utf-8') except Exception: raise ValueError("Couldn't decrypt message.") return plaintext
def validate(self, ciphertext): try: jwe = JWE() jwe.deserialize(ciphertext) if jwe.jose_header != {'alg': 'RSA-OAEP', 'enc': 'A256GCM'}: return False except Exception: return False return True
def set(self, key, value, replace=False): self.protected_header = {'alg': 'dir', 'enc': self.master_enctype} if self.secret_protection != 'encrypt': self.protected_header['custodia.key'] = key protected = json_encode(self.protected_header) jwe = JWE(value, protected) jwe.add_recipient(self.mkey) cvalue = jwe.serialize(compact=True) return self.store.set(key, cvalue, replace)
def get(self, key): value = self.store.get(key) if value is None: return None try: jwe = JWE() jwe.deserialize(value, self.mkey) return jwe.payload.decode('utf-8') except Exception as err: self.logger.error("Error parsing key %s: [%r]" % (key, repr(err))) raise CSStoreError('Error occurred while trying to parse key')
def get(self, key): value = super(EncryptedStore, self).get(key) if value is None: return None try: jwe = JWE() jwe.deserialize(value, self.mkey) return jwe.payload.decode('utf-8') except Exception: self.logger.exception("Error parsing key %s", key) raise CSStoreError('Error occurred while trying to parse key')
def encrypt(message: str, encryption_certificate: JWK) -> str: """Encrypt a message for DCS""" protected_header = { "alg": "RSA-OAEP-256", "enc": "A128CBC-HS256", "typ": "JWE" } jwetoken = JWE(plaintext=message, recipient=encryption_certificate, protected=protected_header) return jwetoken.serialize(compact=True)
def encrypt(self, plaintext, _protected='{"alg":"RSA-OAEP","enc":"A256GCM"}', _public_jwk=None): try: jwe = JWE(plaintext=plaintext, protected=_protected) _public_jwk = _public_jwk if _public_jwk else self._public_jwk jwe.add_recipient(_public_jwk) ciphertext = jwe.serialize(compact=True) except Exception: raise ValueError("Couldn't encrypt message.") return ciphertext
def deserialize(self, jwt, key=None): """Deserialize a JWT token. NOTE: Destroys any current status and tries to import the raw token provided. :param jwt: a 'raw' JWT token. :param key: A (:class:`jwcrypto.jwk.JWK`) verification or decryption key, or a (:class:`jwcrypt.jwk.JWKSet`) that contains a key indexed by the 'kid' header. """ c = jwt.count('.') if c == 2: self.token = JWS() elif c == 4: self.token = JWE() else: raise ValueError("Token format unrecognized") # Apply algs restrictions if any, before performing any operation if self._algs: self.token.allowed_algs = self._algs # now deserialize and also decrypt/verify (or raise) if we # have a key if key is None: self.token.deserialize(jwt, None) elif isinstance(key, JWK): self.token.deserialize(jwt, key) elif isinstance(key, JWKSet): self.token.deserialize(jwt, None) if 'kid' not in self.token.jose_header: raise JWTMissingKeyID('No key ID in JWT header') token_key = key.get_key(self.token.jose_header['kid']) if not token_key: raise JWTMissingKey('Key ID %s not in key set' % self.token.jose_header['kid']) if isinstance(self.token, JWE): self.token.decrypt(token_key) elif isinstance(self.token, JWS): self.token.verify(token_key) else: raise RuntimeError("Unknown Token Type") else: raise ValueError("Unrecognized Key Type") if key is not None: self.header = self.token.jose_header self.claims = self.token.payload.decode('utf-8') self._check_provided_claims()
def deserialize(self, jwt, key=None): """Deserialize a JWT token. NOTE: Destroys any current status and tries to import the raw token provided. :param jwt: a 'raw' JWT token. :param key: A (:class:`jwcrypto.jwk.JWK`) verification or decryption key, or a (:class:`jwcrypto.jwk.JWKSet`) that contains a key indexed by the 'kid' header. """ c = jwt.count('.') if c == 2: self.token = JWS() elif c == 4: self.token = JWE() else: raise ValueError("Token format unrecognized") # Apply algs restrictions if any, before performing any operation if self._algs: self.token.allowed_algs = self._algs # now deserialize and also decrypt/verify (or raise) if we # have a key if key is None: self.token.deserialize(jwt, None) elif isinstance(key, JWK): self.token.deserialize(jwt, key) elif isinstance(key, JWKSet): self.token.deserialize(jwt, None) if 'kid' not in self.token.jose_header: raise JWTMissingKeyID('No key ID in JWT header') token_key = key.get_key(self.token.jose_header['kid']) if not token_key: raise JWTMissingKey('Key ID %s not in key set' % self.token.jose_header['kid']) if isinstance(self.token, JWE): self.token.decrypt(token_key) elif isinstance(self.token, JWS): self.token.verify(token_key) else: raise RuntimeError("Unknown Token Type") else: raise ValueError("Unrecognized Key Type") if key is not None: self.header = self.token.jose_header self.claims = self.token.payload.decode('utf-8') self._check_provided_claims()
def make_encrypted_token(self, key): """Encrypts the payload. Creates a JWE token with the header as the JWE protected header and the claims as the plaintext. See (:class:`jwcrypto.jwe.JWE`) for details on the exceptions that may be reaised. :param key: A (:class:`jwcrypto.jwk.JWK`) key. """ t = JWE(self.claims, self.header) t.add_recipient(key) self.token = t
def encrypt_raw_event(evt, public_key, is_dict=False): payload = evt.to_jsonld() if is_dict is True: public_key = JWK.from_json(json_encode(public_key)) protected_header = { "alg": "RSA-OAEP-256", "enc": "A256CBC-HS512", "typ": "JWE", "kid": public_key.thumbprint(), } data = JWE(payload.encode('utf-8'), recipient=public_key, protected=protected_header) return data.serialize()
def forgotpass(request): if request.user: # already logged in, redirect to home return HTTPFound(location=request.route_url('home')) next_url = request.params.get('next', None) if not next_url: next_url = request.route_url('home') login = '' if 'form.submitted' in request.params: login = request.params.get('email') item = request.dbsession.query(User).filter_by(email=login).first() if item is not None: # Generate link: key = JWK(**loads(request.registry.settings["jwt.secret"])) mins = request.registry.settings["jwt.expire"] payload = dumps({ "id": item.id, "dt": timegm(gmtime()), "hash": hexlify(item.password_hash).decode("utf-8") }) token = JWE(payload.encode('utf-8'), json_encode({ "alg": "A256KW", "enc": "A256CBC-HS512" })) token.add_recipient(key) link = request.route_url("resetpass", jwe=token.serialize(True)) message = Message( subject="VS Leaderboard - Reset Password", recipients=[item.email], body="To reset your password, please click: \n{0}\n".format( link) + "This link will expire in {0} minutes.".format(mins)) request.mailer.send(message) request.session.flash( "s|If that e-mail address is used it will receive a password reset link." ) return dict( url=request.route_url('forgotpass'), next_url=next_url, login=login, )
def encode_jwt(payload: dict, token_type: TokenType) -> str: exp = (settings.JWT_EXPIRATION_DELTA if token_type is TokenType.ACCESS else settings.JWT_REFRESH_EXPIRATION_DELTA) jti_size = (settings.JWT_JTI_SIZE if settings.JWT_BLACKLIST_ENABLED and token_type.value in settings.JWT_BLACKLIST_TOKEN_CHECKS else 0) payload["type"] = token_type.value token = generate_jwt( payload, _secret_key, algorithm=settings.JWT_ALGORITHM, lifetime=exp, jti_size=jti_size, ) if settings.JWT_ENCRYPT: token = JWE( plaintext=token.encode("utf-8"), protected={ "alg": settings.JWE_ALGORITHM, "enc": settings.JWE_ENCRYPTION, "typ": "JWE", }, ) token.add_recipient(_encryption_key) token = token.serialize() return token
def get(self, key): value = self.store.get(key) if value is None: return None try: jwe = JWE() jwe.deserialize(value, self.mkey) value = jwe.payload.decode('utf-8') except Exception as err: self.logger.error("Error parsing key %s: [%r]" % (key, repr(err))) raise CSStoreError('Error occurred while trying to parse key') if self.secret_protection == 'encrypt': return value if 'custodia.key' not in jwe.jose_header: if self.secret_protection == 'migrate': self.set(key, value, replace=True) else: raise CSStoreError('Secret Pinning check failed!' + 'Missing custodia.key element') elif jwe.jose_header['custodia.key'] != key: raise CSStoreError( 'Secret Pinning check failed! Expected {} got {}'.format( key, jwe.jose_header['custodia.key'])) return value
def resetpass(request): if request.user: # already logged in, redirect to home return HTTPFound(location=request.route_url('home')) jwe = request.matchdict.get('jwe') if not jwe: request.session.flash("d|Invalid link.") raise HTTPFound(location=request.route_url('forgotpass')) # decode key = JWK(**loads(request.registry.settings["jwt.secret"])) jwetoken = JWE() try: jwetoken.deserialize(jwe) jwetoken.decrypt(key) except InvalidJWEData: request.session.flash("d|Invalid link?") raise HTTPFound(location=request.route_url('forgotpass')) payload = loads(jwetoken.payload) # check timestamp. nowdt = timegm(gmtime()) if (nowdt - payload["dt"]) > ( int(request.registry.settings["jwt.expire"]) * 60): request.session.flash("d|Link has expired.") raise HTTPFound(location=request.route_url('forgotpass')) # load user... item = request.dbsession.query(User).filter_by(id=payload["id"]).first() if not item: request.session.flash("d|User not found.") raise HTTPFound(location=request.route_url('forgotpass')) # check if password already changed: if item.password_hash != unhexlify(payload["hash"]): request.session.flash("d|Link has expired..") raise HTTPFound(location=request.route_url('forgotpass')) # if submitted: if 'form.submitted' in request.params: password = request.params.get('password') password2 = request.params.get('password2') if modifyUser( request, item, "", "", password, password2, passwordonly=True) is False: return dict(url=request.route_url("resetpass", jwe=jwe)) # if success: request.session.flash("s|Password reset successfully.") return HTTPFound(location=request.route_url('login')) return dict(url=request.route_url("resetpass", jwe=jwe))
def decode_jwt(jwt: str) -> Tuple: """Decode JSON web token. Args: auth_token (str): The JSON web token Raises: JSONWebTokenError: Raised if the signature has expired or if the token is invalid Returns: int: The user id """ if settings.JWT_ENCRYPT: token = JWE() try: token.deserialize(jwt.replace("\\", "")) except InvalidJWEData as error: raise JWEInvalidToken from error try: token.decrypt(_encryption_key) except InvalidJWEData as error: raise JWEDecryptionError from error jwt = token.payload.decode("utf-8") if not settings.JWT_VERIFY: return process_jwt(jwt) try: return verify_jwt( jwt, _secret_key, checks_optional=settings.JWT_VERIFY_EXPIRATION, iat_skew=settings.JWT_LEEWAY, allowed_algs=[settings.JWT_ALGORITHM], ) except (InvalidJWSObject, UnicodeDecodeError) as error: raise JWTDecodeError from error except InvalidJWSSignature as error: raise JWTInvalidSignature from error except Exception as error: raise JWTExpired from error
def mainServer(kierros,PORT,q): if(kierros==0): info = filu_checker() print(info) info = dict(info) url = info['url'] header = info['header'] PORT = int(info['port']) tport = int(info['port']) kierros = 1 HOST = '0.0.0.0' #change to None if wanted listen from IPv6 address while True: s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) except socket.error as msg: print("Main ***",msg) s = None continue try: #print('Main ***',sa) s.bind(sa) s.listen(1) except socket.error as msg: print("Main ***",msg) s.close() s = None continue break if s is None: print('Main *** Could not open socket') time.sleep(10) PORT = PORT+1 mainServer(kierros,PORT,q) #sys.exit(1) conn, addr = s.accept() #print("*" * 60) #print('Main *** Connected by', addr) try: #conn.settimeout(5) data = conn.recv(1024).decode("utf-8") #conn.settimeout(None) except: print("Main *** timeout") mainServer(kierros,PORT,q) #print(data) #datan tarkistus ja säikeen aloitus if data=="I am Client": #print("Main*** Right start message") #lähetetään julkinen avain key = JWK(generate="RSA",public_exponent=29,size=1000) public_key = key.export_public() conn.send(public_key.encode("utf-8")) #otetaan viesti vastaan ja avataan encrypted_signed_token = conn.recv(1024).decode("utf-8") #print(encrypted_signed_token) try: E = JWE() E.deserialize(encrypted_signed_token, key) raw_payload = E.payload #print("*** raw payload:",raw_payload) string = raw_payload.decode("utf-8") except Exception as msg: print('Main *** Wrong key',encrypted_signed_token) print('Main *** Wrong key',public_key) print('Main *** Wrong key',msg) break #print("*** received str:", string) Payload = json.loads(string) #print("*** JSON:",Payload) #print("*** received payload:", Payload['exp']) while True: try: #käydään kysymässä onko listoilla mac = str(Payload['exp']) #Tähän kohti kysymys lähetetään request session ohjelmalle myResponse = Check_rest(url,mac,header) #myResponse = requests.get(url + mac,header) #print(url + mac,header) #print("REST:", myResponse.status_code) break except Exception as msg: print("Main *** REST failed",msg) sys.exit(1) if(myResponse == 200): #if(mac=='mac=00-00-00-00-00-01'): #print("Main *** Found!") #jData = json.loads(myResponse.content.decode("utf-8")) #print("The response contains {0} properties".format(len(jData))) jData = 'mac=00-00-00-00-00-01' #Kontrollerille viestiä, id configuroitavissa #{ #ip: string, #valid: bool #} #POST /iot-service/:id #Haetaan "listalta" if not q.empty(): free_port = q.get() conn.send(free_port.encode("utf-8")) else: tport = str(int(tport)+1) conn.send(tport.encode("utf-8")) #Aloitetaan stringissä uusi yhteys #conn.shutdown(socket.SHUT_RDWR) conn.close() thread.start_new_thread(Listen_Client,(url,data,tport,q,header,)) else: print("Not found",myResponse.status_code) answer="Good try <3" conn.send(answer.encode("utf-8")) break else: conn.close() print("*" * 60) conn.close() print("*" * 60)
def Listen_Client(url,data,tport,q,header): try: while True: HOST = '0.0.0.0' PORT = tport s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) except socket.error as msg: print("Thread *** error message:",msg) s = None sys.exit(1) continue try: print("Thread",sa) s.bind(sa) s.listen(1) except socket.error as msg: print("Thread *** error message:",msg) s.close() s = None sys.exit(1) continue break if s is None: print("Thread *** could not open socket") break conn, addr = s.accept() while True: print("-" * 60) print('Thread *** connected by', addr) key = JWK(generate="RSA",public_exponent=29,size=1000) public_key = key.export_public() print('Thread *** public key',public_key) conn.send(public_key.encode("utf-8")) #otetaan viesti vastaan ja avataan try: conn.settimeout(20) encrypted_signed_token = conn.recv(1024).decode("utf-8") print(encrypted_signed_token) except: print('Thread *** time out') q.put(tport) break E = JWE() E.deserialize(encrypted_signed_token, key) raw_payload = E.payload string = raw_payload.decode("utf-8") Payload = json.loads(string) #print("Thread *** received payload:", Payload['exp']) while True: try: #käydään REST app kysymässä Kumokselta mac = str(Payload['exp']) myResponse = requests.get(url + mac,header) break except: print("Thread *** REST failed") print(url + mac,header) print("Thread *** REST:", myResponse.status_code) #tarkistus if(myResponse.ok): print("Thread *** Found!") jData = json.loads(myResponse.content.decode("utf-8")) print("The response contains {0} properties".format(len(jData))) elif myResponse.status_code==400: print("Baasbox is down or configuration file is wrong") break else: print("Thread *** Not found") answer="Good try <3" conn.send(answer.encode("utf-8")) q.put(tport) #SDN irrottaa kyseisen laitteen verkosta break conn.close() #break print("Thread *** end") print("-" * 60) except Exception as msg: print("Thread *** Forced end") print(msg) print("-" * 60)
def mainServer(q): filu = 'serverdaemon.ini' HOST = '0.0.0.0' #change to None if wanted listen from IPv6 address try: fp = open(filu, 'r+') Config.readfp(fp) url = Config.get('REST','url') header = Config.get('REST','header') tport = int(Config.get('DAEMON','port')) PORT = int(Config.get('DAEMON','port')) fp.close() except: filu = input('anna kansion nimi:') url = input('anna url:') header = input('anna header:') port = input('anna port:') cfgfile = open(filu,'w') try: Config.add_section('REST') Config.add_section('DAEMON') print("*** Created sections") except: print('*** sections already exists') Config.set('REST','url',url) Config.set('REST','header', header) Config.set('DAEMON','port',port) Config.write(cfgfile) cfgfile.close() tport = int(Config.get('DAEMON','port')) url = Config.get('REST','url') header = Config.get('REST','header') PORT = int(Config.get('DAEMON','port')) print("*** Created information.") header = ast.literal_eval(header) while True: s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) s.setsockopt(socket.SOL_SOCKET,socket.SO_REUSEADDR,1) except socket.error as msg: s = None continue try: #print('Main ***',sa) s.bind(sa) s.listen(1) except socket.error as msg: s.close() s = None continue break if s is None: print('Main *** Could not open socket') mainServer(q) #sys.exit(1) conn, addr = s.accept() print("*" * 60) print('Main *** Connected by', addr) try: conn.settimeout(5) data = conn.recv(1024).decode("utf-8") conn.settimeout(None) except: print("Main *** timeout") mainServer(q) print(data) #datan tarkistus ja säikeen aloitus if data=="I am Client": print("Main*** Right start message") #lähetetään julkinen avain key = JWK(generate="RSA",public_exponent=29,size=1000) public_key = key.export_public() conn.send(public_key.encode("utf-8")) #otetaan viesti vastaan ja avataan encrypted_signed_token = conn.recv(1024).decode("utf-8") print(encrypted_signed_token) E = JWE() E.deserialize(encrypted_signed_token, key) raw_payload = E.payload print("*** raw payload:",raw_payload) string = raw_payload.decode("utf-8") print("*** received str:", string) Payload = json.loads(string) print("*** JSON:",Payload) print("*** received payload:", Payload['exp']) while True: try: #käydään kysymässä onko listoilla mac = str(Payload['exp']) myResponse = requests.get(url + mac,header) print(url + mac,header) print("REST:", myResponse.status_code) break except: print("Main *** REST failed") if(myResponse.ok): print("Main *** Found!") jData = json.loads(myResponse.content.decode("utf-8")) print("The response contains {0} properties".format(len(jData))) #Kontrollerille viestiä, id configuroitavissa #{ #ip: string, #valid: bool #} #POST /iot-service/:id #Haetaan "listalta" if not q.empty(): free_port = q.get() conn.send(free_port.encode("utf-8")) else: tport = str(int(tport)+1) conn.send(tport.encode("utf-8")) #Aloitetaan stringissä uusi yhteys #conn.shutdown(socket.SHUT_RDWR) conn.close() thread.start_new_thread(Listen_Client,(url,data,tport,q,header,)) elif myResponse.status_code==400: print("Baasbox is down or configuration file is wrong") break else: print("Not found") answer="Good try <3" conn.send(answer.encode("utf-8")) break else: conn.close() print("*" * 60) conn.close() print("*" * 60)
def make_enc_kem(name, value, sig_key, alg, enc_key, enc): plaintext = make_sig_kem(name, value, sig_key, alg) eprot = {'kid': enc_key.key_id, 'alg': enc[0], 'enc': enc[1]} jwe = JWE(plaintext, json_encode(eprot)) jwe.add_recipient(enc_key) return jwe.serialize(compact=True)
def set(self, key, value, replace=False): jwe = JWE(value, json_encode({'alg': 'dir', 'enc': self.enc})) jwe.add_recipient(self.mkey) cvalue = jwe.serialize(compact=True) return super(EncryptedStore, self).set(key, cvalue, replace)
def set(self, key, value, replace=False): protected = json_encode({'alg': 'dir', 'enc': self.master_enctype}) jwe = JWE(value, protected) jwe.add_recipient(self.mkey) cvalue = jwe.serialize(compact=True) return super(EncryptedStore, self).set(key, cvalue, replace)
def mainServer(q): filu = 'serverdaemon.ini' HOST = '0.0.0.0' #change to None if wanted listen from IPv6 address try: fp = open(filu, 'r+') Config.readfp(fp) url = Config.get('REST', 'url') header = Config.get('REST', 'header') tport = int(Config.get('DAEMON', 'port')) PORT = int(Config.get('DAEMON', 'port')) fp.close() except: filu = input('anna kansion nimi:') url = input('anna url:') header = input('anna header:') port = input('anna port:') cfgfile = open(filu, 'w') try: Config.add_section('REST') Config.add_section('DAEMON') print("*** Created sections") except: print('*** sections already exists') Config.set('REST', 'url', url) Config.set('REST', 'header', header) Config.set('DAEMON', 'port', port) Config.write(cfgfile) cfgfile.close() tport = int(Config.get('DAEMON', 'port')) url = Config.get('REST', 'url') header = Config.get('REST', 'header') PORT = int(Config.get('DAEMON', 'port')) print("*** Created information.") header = ast.literal_eval(header) while True: s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except socket.error as msg: s = None continue try: #print('Main ***',sa) s.bind(sa) s.listen(1) except socket.error as msg: s.close() s = None continue break if s is None: print('Main *** Could not open socket') mainServer(q) #sys.exit(1) conn, addr = s.accept() print("*" * 60) print('Main *** Connected by', addr) try: conn.settimeout(5) data = conn.recv(1024).decode("utf-8") conn.settimeout(None) except: print("Main *** timeout") mainServer(q) print(data) #datan tarkistus ja säikeen aloitus if data == "I am Client": print("Main*** Right start message") #lähetetään julkinen avain key = JWK(generate="RSA", public_exponent=29, size=1000) public_key = key.export_public() conn.send(public_key.encode("utf-8")) #otetaan viesti vastaan ja avataan encrypted_signed_token = conn.recv(1024).decode("utf-8") print(encrypted_signed_token) E = JWE() E.deserialize(encrypted_signed_token, key) raw_payload = E.payload print("*** raw payload:", raw_payload) string = raw_payload.decode("utf-8") print("*** received str:", string) Payload = json.loads(string) print("*** JSON:", Payload) print("*** received payload:", Payload['exp']) while True: try: #käydään kysymässä onko listoilla mac = str(Payload['exp']) myResponse = requests.get(url + mac, header) print(url + mac, header) print("REST:", myResponse.status_code) break except: print("Main *** REST failed") if (myResponse.ok): print("Main *** Found!") jData = json.loads(myResponse.content.decode("utf-8")) print("The response contains {0} properties".format( len(jData))) #Kontrollerille viestiä, id configuroitavissa #{ #ip: string, #valid: bool #} #POST /iot-service/:id #Haetaan "listalta" if not q.empty(): free_port = q.get() conn.send(free_port.encode("utf-8")) else: tport = str(int(tport) + 1) conn.send(tport.encode("utf-8")) #Aloitetaan stringissä uusi yhteys #conn.shutdown(socket.SHUT_RDWR) conn.close() thread.start_new_thread(Listen_Client, ( url, data, tport, q, header, )) elif myResponse.status_code == 400: print("Baasbox is down or configuration file is wrong") break else: print("Not found") answer = "Good try <3" conn.send(answer.encode("utf-8")) break else: conn.close() print("*" * 60) conn.close() print("*" * 60)
def decrypt(message: str, encryption_key: JWK) -> str: """Decrypt a response from DCS""" jwetoken = JWE() jwetoken.deserialize(raw_jwe=message, key=encryption_key) return jwetoken.payload.decode("utf-8")
def make_enc_kem(name, value, sig_key, alg, enc_key, enc): plaintext = make_sig_kem(name, value, sig_key, alg) eprot = {"kid": enc_key.key_id, "alg": enc[0], "enc": enc[1]} E = JWE(plaintext, json_encode(eprot)) E.add_recipient(enc_key) return E.serialize(compact=True)
def decrypt_and_decode(raw_string, key_pair): token = JWE() token.deserialize(raw_string, key=key_pair['private']) return token.payload
def set(self, key, value, replace=False): jwe = JWE(value, json_encode({'alg': 'dir', 'enc': self.enc})) jwe.add_recipient(self.mkey) cvalue = jwe.serialize(compact=True) return self.store.set(key, cvalue, replace)
def ServerMain(q,tport): filu = 'serverdaemon.ini' HOST = '0.0.0.0' #change to None if wanted listen from IPv6 address try: fp = open(filu, 'r+') Config.readfp(fp) url = Config.get('REST','url') header = Config.get('REST','header') if tport==0: tport = int(Config.get('DAEMON','port')) PORT = int(Config.get('DAEMON','port')) fp.close() except: url = input('anna url:') header = input('anna header:') port = input('anna port:') cfgfile = open(filu,'w') try: Config.add_section('REST') Config.add_section('DAEMON') print("*** Created sections") except: print('*** sections already exists') Config.set('REST','url',url) Config.set('REST','header', header) Config.set('DAEMON','port',port) Config.write(cfgfile) cfgfile.close() tport = int(Config.get('DAEMON','port')) url = Config.get('REST','url') header = Config.get('REST','header') PORT = int(Config.get('DAEMON','port')) print("*** Created information.") header = ast.literal_eval(header) try: conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) while True: print("*** Main ***") #print("*" * 60) conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: conn.bind((HOST, PORT)) except: print("Main *** Ei onnistunut") ServerMain(q,tport) info = conn.recvfrom(1024) #print(info) data = info[0].decode("utf-8") #print (data) addr = info[1] #print (addr) #datan tarkistus ja säikeen aloitus if data=="I am Client": #print("Main *** Right start message") #lähetetään julkinen avain key = JWK(generate="RSA",public_exponent=29,size=1000) public_key = key.export_public() conn.sendto(public_key.encode("utf-8"),addr) #otetaan viesti vastaan ja avataan encrypted_signed_token = conn.recv(1024).decode("utf-8") #print(encrypted_signed_token) E = JWE() E.deserialize(encrypted_signed_token, key) raw_payload = E.payload #print("*** raw payload:",raw_payload) string = raw_payload.decode("utf-8") #print("*** received str:", string) Payload = json.loads(string) #print("*** JSON:",Payload) #print("*** received payload:", Payload['exp']) #käydään REST app kysymässä Kumokselta mac = str(Payload['exp']) myResponse = requests.get(url + mac,header) #print(url + mac,header) #print("REST:", myResponse.status_code) if(myResponse.ok): print("main *** Found!") jData = json.loads(myResponse.content.decode("utf-8")) #print("The response contains {0} properties".format(len(jData))) # Konrollerille yhteys #Haetaan "listalta" if not q.empty(): tport = q.get() conn.sendto(tport.encode("utf-8"),addr) else: tport = str(int(tport)+1) conn.sendto(tport.encode("utf-8"),addr) #Aloitetaan stringissä uusi yhteys thread.start_new_thread(Listen_Client,(url,data,tport,q,header,)) else: print("Main *** Not found") answer="Good try <3" conn.sendto(answer.encode("utf-8"),addr) else: conn.close() print("*" * 60) conn.close() print("*" * 60) except: conn.close() print("Main *** Frong message. Start again") ServerMain(q,tport)
def deserialize(self, jwt, key=None): """Deserialize a JWT token. NOTE: Destroys any current status and tries to import the raw token provided. :param jwt: a 'raw' JWT token. :param key: A (:class:`jwcrypto.jwk.JWK`) verification or decryption key, or a (:class:`jwcrypto.jwk.JWKSet`) that contains a key indexed by the 'kid' header. """ c = jwt.count('.') if c == 2: self.token = JWS() elif c == 4: self.token = JWE() else: raise ValueError("Token format unrecognized") # Apply algs restrictions if any, before performing any operation if self._algs: self.token.allowed_algs = self._algs self.deserializelog = list() # now deserialize and also decrypt/verify (or raise) if we # have a key if key is None: self.token.deserialize(jwt, None) elif isinstance(key, JWK): self.token.deserialize(jwt, key) self.deserializelog.append("Success") elif isinstance(key, JWKSet): self.token.deserialize(jwt, None) if 'kid' in self.token.jose_header: kid_key = key.get_key(self.token.jose_header['kid']) if not kid_key: raise JWTMissingKey('Key ID %s not in key set' % self.token.jose_header['kid']) self.token.deserialize(jwt, kid_key) else: for k in key: try: self.token.deserialize(jwt, k) self.deserializelog.append("Success") break except Exception as e: # pylint: disable=broad-except keyid = k.key_id if keyid is None: keyid = k.thumbprint() self.deserializelog.append('Key [%s] failed: [%s]' % ( keyid, repr(e))) continue if "Success" not in self.deserializelog: raise JWTMissingKey('No working key found in key set') else: raise ValueError("Unrecognized Key Type") if key is not None: self.header = self.token.jose_header self.claims = self.token.payload.decode('utf-8') self._check_provided_claims()
def set(self, key, value, replace=False): protected = json_encode({'alg': 'dir', 'enc': self.master_enctype}) jwe = JWE(value, protected) jwe.add_recipient(self.mkey) cvalue = jwe.serialize(compact=True) return self.store.set(key, cvalue, replace)
def Listen_Client(url,data,tport,q,header): try: while True: #print("---Thread---") HOST = '0.0.0.0' PORT = int(tport) conn = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) try: conn.bind((HOST, PORT)) print("Thread *** Bind is ready", PORT) except: print("Thread *** Connection bind failed") Listen_Client(url,data,PORT,q,header) info = conn.recvfrom(1024) #print(info) data = info[0].decode("utf-8") #print (data) addr = info[1] #print (addr) #print("-" * 60) #print('Thread *** connected by', addr) key = JWK(generate="RSA",public_exponent=29,size=1000) public_key = key.export_public() #print('Thread *** public key',public_key) conn.sendto(public_key.encode("utf-8"),addr) #otetaan viesti vastaan ja avataan try: conn.settimeout(60) encrypted_signed_token_info = conn.recvfrom(1024) encrypted_signed_token = encrypted_signed_token_info[0].decode("utf-8") #print(encrypted_signed_token) except: print('Thread *** time out') break E = JWE() E.deserialize(encrypted_signed_token, key) raw_payload = E.payload string = raw_payload.decode("utf-8") Payload = json.loads(string) #print("Thread *** received payload:", Payload['exp']) #käydään REST app kysymässä Kumokselta mac = str(Payload['exp']) myResponse = requests.get(url + mac,header) #print(url + mac,header) #print("Thread *** REST:", myResponse.status_code) #tarkistus if(myResponse.ok): print("Thread *** Found!") jData = json.loads(myResponse.content.decode("utf-8")) #print("The response contains {0} properties".format(len(jData))) conn.close() else: print("Thread *** Not found") answer="Good try <3" conn.send(answer.encode("utf-8")) #SDN irrottaa kyseisen laitteen verkosta break conn.close() #conn.close() print("Thread *** end") q.put(tport) except: #conn.close() q.put(tport) print("Thread *** Forced end")
def mainServer(kierros, PORT, q): if (kierros == 0): info = filu_checker() print(info) info = dict(info) url = info['url'] header = info['header'] PORT = int(info['port']) tport = int(info['port']) kierros = 1 HOST = '0.0.0.0' #change to None if wanted listen from IPv6 address while True: s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except socket.error as msg: print("Main ***", msg) s = None continue try: #print('Main ***',sa) s.bind(sa) s.listen(1) except socket.error as msg: print("Main ***", msg) s.close() s = None continue break if s is None: print('Main *** Could not open socket') time.sleep(10) PORT = PORT + 1 mainServer(kierros, PORT, q) #sys.exit(1) conn, addr = s.accept() #print("*" * 60) #print('Main *** Connected by', addr) try: #conn.settimeout(5) data = conn.recv(1024).decode("utf-8") #conn.settimeout(None) except: print("Main *** timeout") mainServer(kierros, PORT, q) #print(data) #datan tarkistus ja säikeen aloitus if data == "I am Client": #print("Main*** Right start message") #lähetetään julkinen avain key = JWK(generate="RSA", public_exponent=29, size=1000) public_key = key.export_public() conn.send(public_key.encode("utf-8")) #otetaan viesti vastaan ja avataan encrypted_signed_token = conn.recv(1024).decode("utf-8") #print(encrypted_signed_token) try: E = JWE() E.deserialize(encrypted_signed_token, key) raw_payload = E.payload #print("*** raw payload:",raw_payload) string = raw_payload.decode("utf-8") except Exception as msg: print('Main *** Wrong key', encrypted_signed_token) print('Main *** Wrong key', public_key) print('Main *** Wrong key', msg) break #print("*** received str:", string) Payload = json.loads(string) #print("*** JSON:",Payload) #print("*** received payload:", Payload['exp']) while True: try: #käydään kysymässä onko listoilla mac = str(Payload['exp']) #Tähän kohti kysymys lähetetään request session ohjelmalle myResponse = Check_rest(url, mac, header) #myResponse = requests.get(url + mac,header) #print(url + mac,header) #print("REST:", myResponse.status_code) break except Exception as msg: print("Main *** REST failed", msg) sys.exit(1) if (myResponse == 200): #if(mac=='mac=00-00-00-00-00-01'): #print("Main *** Found!") #jData = json.loads(myResponse.content.decode("utf-8")) #print("The response contains {0} properties".format(len(jData))) jData = 'mac=00-00-00-00-00-01' #Kontrollerille viestiä, id configuroitavissa #{ #ip: string, #valid: bool #} #POST /iot-service/:id #Haetaan "listalta" if not q.empty(): free_port = q.get() conn.send(free_port.encode("utf-8")) else: tport = str(int(tport) + 1) conn.send(tport.encode("utf-8")) #Aloitetaan stringissä uusi yhteys #conn.shutdown(socket.SHUT_RDWR) conn.close() thread.start_new_thread(Listen_Client, ( url, data, tport, q, header, )) else: print("Not found", myResponse.status_code) answer = "Good try <3" conn.send(answer.encode("utf-8")) break else: conn.close() print("*" * 60) conn.close() print("*" * 60)
class JWT(object): """JSON Web token object This object represent a generic token. """ def __init__(self, header=None, claims=None, jwt=None, key=None, algs=None, default_claims=None, check_claims=None): """Creates a JWT object. :param header: A dict or a JSON string with the JWT Header data. :param claims: A dict or a string with the JWT Claims data. :param jwt: a 'raw' JWT token :param key: A (:class:`jwcrypto.jwk.JWK`) key to deserialize the token. A (:class:`jwcrypto.jwk.JWKSet`) can also be used. :param algs: An optional list of allowed algorithms :param default_claims: An optional dict with default values for registred claims. A None value for NumericDate type claims will cause generation according to system time. Only the values from RFC 7519 - 4.1 are evaluated. :param check_claims: An optional dict of claims that must be present in the token, if the value is not None the claim must match exactly. Note: either the header,claims or jwt,key parameters should be provided as a deserialization operation (which occurs if the jwt is provided will wipe any header os claim provided by setting those obtained from the deserialization of the jwt token. Note: if check_claims is not provided the 'exp' and 'nbf' claims are checked if they are set on the token but not enforced if not set. Any other RFC 7519 registered claims are checked only for format conformance. """ self._header = None self._claims = None self._token = None self._algs = algs self._reg_claims = None self._check_claims = None self._leeway = 60 # 1 minute clock skew allowed self._validity = 600 # 10 minutes validity (up to 11 with leeway) if header: self.header = header if default_claims is not None: self._reg_claims = default_claims if check_claims is not None: self._check_claims = check_claims if claims: self.claims = claims if jwt is not None: self.deserialize(jwt, key) @property def header(self): if self._header is None: raise KeyError("'header' not set") return self._header @header.setter def header(self, h): if isinstance(h, dict): self._header = json_encode(h) else: self._header = h @property def claims(self): if self._claims is None: raise KeyError("'claims' not set") return self._claims @claims.setter def claims(self, c): if self._reg_claims and not isinstance(c, dict): # decode c so we can set default claims c = json_decode(c) if isinstance(c, dict): self._add_default_claims(c) self._claims = json_encode(c) else: self._claims = c @property def token(self): return self._token @token.setter def token(self, t): if isinstance(t, JWS) or isinstance(t, JWE) or isinstance(t, JWT): self._token = t else: raise TypeError("Invalid token type, must be one of JWS,JWE,JWT") @property def leeway(self): return self._leeway @leeway.setter def leeway(self, l): self._leeway = int(l) @property def validity(self): return self._validity @validity.setter def validity(self, v): self._validity = int(v) def _add_optional_claim(self, name, claims): if name in claims: return val = self._reg_claims.get(name, None) if val is not None: claims[name] = val def _add_time_claim(self, name, claims, defval): if name in claims: return if name in self._reg_claims: if self._reg_claims[name] is None: claims[name] = defval else: claims[name] = self._reg_claims[name] def _add_jti_claim(self, claims): if 'jti' in claims or 'jti' not in self._reg_claims: return claims['jti'] = uuid.uuid4() def _add_default_claims(self, claims): if self._reg_claims is None: return now = int(time.time()) self._add_optional_claim('iss', claims) self._add_optional_claim('sub', claims) self._add_optional_claim('aud', claims) self._add_time_claim('exp', claims, now + self.validity) self._add_time_claim('nbf', claims, now) self._add_time_claim('iat', claims, now) self._add_jti_claim(claims) def _check_string_claim(self, name, claims): if name not in claims: return if not isinstance(claims[name], string_types): raise JWTInvalidClaimFormat("Claim %s is not a StringOrURI type") def _check_array_or_string_claim(self, name, claims): if name not in claims: return if isinstance(claims[name], list): if any(not isinstance(claim, string_types) for claim in claims): raise JWTInvalidClaimFormat( "Claim %s contains non StringOrURI types" % (name, )) elif not isinstance(claims[name], string_types): raise JWTInvalidClaimFormat("Claim %s is not a StringOrURI type" % (name, )) def _check_integer_claim(self, name, claims): if name not in claims: return try: int(claims[name]) except ValueError: raise JWTInvalidClaimFormat("Claim %s is not an integer" % (name, )) def _check_exp(self, claim, limit, leeway): if claim < limit - leeway: raise JWTExpired('Expired at %d, time: %d(leeway: %d)' % (claim, limit, leeway)) def _check_nbf(self, claim, limit, leeway): if claim > limit + leeway: raise JWTNotYetValid('Valid from %d, time: %d(leeway: %d)' % (claim, limit, leeway)) def _check_default_claims(self, claims): self._check_string_claim('iss', claims) self._check_string_claim('sub', claims) self._check_array_or_string_claim('aud', claims) self._check_integer_claim('exp', claims) self._check_integer_claim('nbf', claims) self._check_integer_claim('iat', claims) self._check_string_claim('jti', claims) if self._check_claims is None: if 'exp' in claims: self._check_exp(claims['exp'], time.time(), self._leeway) if 'nbf' in claims: self._check_nbf(claims['nbf'], time.time(), self._leeway) def _check_provided_claims(self): # check_claims can be set to False to skip any check if self._check_claims is False: return try: claims = json_decode(self.claims) if not isinstance(claims, dict): raise ValueError() except ValueError: if self._check_claims is not None: raise JWTInvalidClaimFormat( "Claims check requested but claims is not a json dict") return self._check_default_claims(claims) if self._check_claims is None: return for name, value in self._check_claims.items(): if name not in claims: raise JWTMissingClaim("Claim %s is missing" % (name, )) if name in ['iss', 'sub', 'jti']: if value is not None and value != claims[name]: raise JWTInvalidClaimValue( "Invalid '%s' value. Expected '%s' got '%s'" % (name, value, claims[name])) elif name == 'aud': if value is not None: if value == claims[name]: continue if isinstance(claims[name], list): if value in claims[name]: continue raise JWTInvalidClaimValue( "Invalid '%s' value. Expected '%s' in '%s'" % (name, value, claims[name])) elif name == 'exp': if value is not None: self._check_exp(claims[name], value, 0) else: self._check_exp(claims[name], time.time(), self._leeway) elif name == 'nbf': if value is not None: self._check_nbf(claims[name], value, 0) else: self._check_nbf(claims[name], time.time(), self._leeway) else: if value is not None and value != claims[name]: raise JWTInvalidClaimValue( "Invalid '%s' value. Expected '%s' got '%s'" % (name, value, claims[name])) def make_signed_token(self, key): """Signs the payload. Creates a JWS token with the header as the JWS protected header and the claims as the payload. See (:class:`jwcrypto.jws.JWS`) for details on the exceptions that may be reaised. :param key: A (:class:`jwcrypto.jwk.JWK`) key. """ t = JWS(self.claims) t.add_signature(key, protected=self.header) self.token = t def make_encrypted_token(self, key): """Encrypts the payload. Creates a JWE token with the header as the JWE protected header and the claims as the plaintext. See (:class:`jwcrypto.jwe.JWE`) for details on the exceptions that may be reaised. :param key: A (:class:`jwcrypto.jwk.JWK`) key. """ t = JWE(self.claims, self.header) t.add_recipient(key) self.token = t def deserialize(self, jwt, key=None): """Deserialize a JWT token. NOTE: Destroys any current status and tries to import the raw token provided. :param jwt: a 'raw' JWT token. :param key: A (:class:`jwcrypto.jwk.JWK`) verification or decryption key, or a (:class:`jwcrypto.jwk.JWKSet`) that contains a key indexed by the 'kid' header. """ c = jwt.count('.') if c == 2: self.token = JWS() elif c == 4: self.token = JWE() else: raise ValueError("Token format unrecognized") # Apply algs restrictions if any, before performing any operation if self._algs: self.token.allowed_algs = self._algs # now deserialize and also decrypt/verify (or raise) if we # have a key if key is None: self.token.deserialize(jwt, None) elif isinstance(key, JWK): self.token.deserialize(jwt, key) elif isinstance(key, JWKSet): self.token.deserialize(jwt, None) if 'kid' not in self.token.jose_header: raise JWTMissingKeyID('No key ID in JWT header') token_key = key.get_key(self.token.jose_header['kid']) if not token_key: raise JWTMissingKey('Key ID %s not in key set' % self.token.jose_header['kid']) if isinstance(self.token, JWE): self.token.decrypt(token_key) elif isinstance(self.token, JWS): self.token.verify(token_key) else: raise RuntimeError("Unknown Token Type") else: raise ValueError("Unrecognized Key Type") if key is not None: self.header = self.token.jose_header self.claims = self.token.payload.decode('utf-8') self._check_provided_claims() def serialize(self, compact=True): """Serializes the object into a JWS token. :param compact(boolean): must be True. Note: the compact parameter is provided for general compatibility with the serialize() functions of :class:`jwcrypto.jws.JWS` and :class:`jwcrypto.jwe.JWE` so that these objects can all be used interchangeably. However the only valid JWT representtion is the compact representation. """ return self.token.serialize(compact)
def Listen_Client(url, data, tport, q, header): try: while True: HOST = '0.0.0.0' PORT = tport s = None for res in socket.getaddrinfo(HOST, PORT, socket.AF_UNSPEC, socket.SOCK_STREAM, 0, socket.AI_PASSIVE): af, socktype, proto, canonname, sa = res try: s = socket.socket(af, socktype, proto) s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) except socket.error as msg: #print(PORT,"Thread *** error message:",msg) s = None sys.exit(1) continue try: #print("Thread",sa) s.bind(sa) s.listen(1) except socket.error as msg: print(PORT, "Thread *** error message:", msg) s.close() s = None sys.exit(1) continue break if s is None: print(PORT, "Thread *** could not open socket") break conn, addr = s.accept() while True: #print("-" * 60) #print('Thread *** connected by', addr) key = JWK(generate="RSA", public_exponent=29, size=1000) public_key = key.export_public() #print('Thread *** public key',public_key) conn.send(public_key.encode("utf-8")) #otetaan viesti vastaan ja avataan try: conn.settimeout(20) encrypted_signed_token = conn.recv(1024).decode("utf-8") #print(encrypted_signed_token) except: print(PORT, 'Thread *** time out') q.put(tport) break try: E = JWE() E.deserialize(encrypted_signed_token, key) except Exception as msg: print(PORT, 'Thread *** Wrong key', encrypted_signed_token) print(PORT, 'Thread *** Wrong key', public_key) print(PORT, 'Thread *** Wrong key', msg) break raw_payload = E.payload string = raw_payload.decode("utf-8") Payload = json.loads(string) #print("Thread *** received payload:", Payload['exp']) while True: try: #käydään REST app kysymässä Kumokselta mac = str(Payload['exp']) #myResponse = requests.get(url + mac,header) myResponse = Check_rest(url, mac, header) break except Exception as msg: print(PORT, "Thread *** REST failed", msg) #print(url + mac,header) #print("Thread *** REST:", myResponse.status_code) #tarkistus if (myResponse == 200): #if(mac=='mac=00-00-00-00-00-01'): #print("Thread *** Found!") jData = "mac=00-00-00-00-00-01" #jData = json.loads(myResponse.content.decode("utf-8")) #print("The response contains {0} properties".format(len(jData))) else: print("Thread *** Not found") answer = "Good try <3" conn.send(answer.encode("utf-8")) q.put(tport) #SDN irrottaa kyseisen laitteen verkosta break conn.close() #break print(PORT, "Thread *** end") print("-" * 60) except Exception as msg: print(PORT, "Thread *** Forced end", msg) print("-" * 60)
class JWT(object): """JSON Web token object This object represent a generic token. """ def __init__(self, header=None, claims=None, jwt=None, key=None, algs=None, default_claims=None, check_claims=None): """Creates a JWT object. :param header: A dict or a JSON string with the JWT Header data. :param claims: A dict or a string withthe JWT Claims data. :param jwt: a 'raw' JWT token :param key: A (:class:`jwcrypto.jwk.JWK`) key to deserialize the token. :param algs: An optional list of allowed algorithms :param default_claims: An optional dict with default values for registred claims. A None value for NumericDate type claims will cause generation according to system time. Only the values fro RFC 7519 - 4.1 are evaluated. :param check_claims: An optional dict of claims that must be present in the token, if the value is not None the claim must match exactly. Note: either the header,claims or jwt,key parameters should be provided as a deserialization operation (which occurs if the jwt is provided will wipe any header os claim provided by setting those obtained from the deserialization of the jwt token. Note: if check_claims is not provided the 'exp' and 'nbf' claims are checked if they are set on the token but not enforced if not set. Any other RFC 7519 registered claims are checked only for format conformance. """ self._header = None self._claims = None self._token = None self._algs = algs self._reg_claims = None self._check_claims = None self._leeway = 60 # 1 minute clock skew allowed self._validity = 600 # 10 minutes validity (up to 11 with leeway) if header: self.header = header if claims: self.claims = claims if default_claims is not None: self._reg_claims = default_claims if check_claims is not None: self._check_claims = check_claims if jwt is not None: self.deserialize(jwt, key) @property def header(self): if self._header is None: raise KeyError("'header' not set") return self._header @header.setter def header(self, h): if isinstance(h, dict): self._header = json_encode(h) else: self._header = h @property def claims(self): if self._claims is None: raise KeyError("'claims' not set") return self._claims @claims.setter def claims(self, c): if isinstance(c, dict): self._add_default_claims(c) self._claims = json_encode(c) else: self._claims = c @property def token(self): return self._token @token.setter def token(self, t): if isinstance(t, JWS) or isinstance(t, JWE) or isinstance(t, JWT): self._token = t else: raise TypeError("Invalid token type, must be one of JWS,JWE,JWT") @property def leeway(self): return self._leeway @leeway.setter def leeway(self, l): self._leeway = int(l) @property def validity(self): return self._validity @validity.setter def validity(self, v): self._validity = int(v) def _add_optional_claim(self, name, claims): if name in claims: return val = self._reg_claims.get(name, None) if val is not None: claims[name] = val def _add_time_claim(self, name, claims, defval): if name in claims: return if name in self._reg_claims: if self._reg_claims[name] is None: claims[name] = defval else: claims[name] = self._reg_claims[name] def _add_jti_claim(self, claims): if 'jti' in claims or 'jti' not in self._reg_claims: return claims['jti'] = uuid.uuid4() def _add_default_claims(self, claims): if self._reg_claims is None: return now = int(time.time()) self._add_optional_claim('iss', claims) self._add_optional_claim('sub', claims) self._add_optional_claim('aud', claims) self._add_time_claim('exp', claims, now + self.validity) self._add_time_claim('nbf', claims, now) self._add_time_claim('iat', claims, now) self._add_jti_claim(claims) def _check_string_claim(self, name, claims): if name not in claims: return if not isinstance(claims[name], string_types): raise JWTInvalidClaimFormat("Claim %s is not a StringOrURI type") def _check_array_or_string_claim(self, name, claims): if name not in claims: return if isinstance(claims[name], list): if any(not isinstance(claim, string_types) for claim in claims): raise JWTInvalidClaimFormat( "Claim %s contains non StringOrURI types" % (name, )) elif not isinstance(claims[name], string_types): raise JWTInvalidClaimFormat( "Claim %s is not a StringOrURI type" % (name, )) def _check_integer_claim(self, name, claims): if name not in claims: return try: int(claims[name]) except ValueError: raise JWTInvalidClaimFormat( "Claim %s is not an integer" % (name, )) def _check_exp(self, claim, limit, leeway): if claim < limit - leeway: raise JWTExpired('Expired at %d, time: %d(leeway: %d)' % ( claim, limit, leeway)) def _check_nbf(self, claim, limit, leeway): if claim > limit + leeway: raise JWTNotYetValid('Valid from %d, time: %d(leeway: %d)' % ( claim, limit, leeway)) def _check_default_claims(self, claims): self._check_string_claim('iss', claims) self._check_string_claim('sub', claims) self._check_array_or_string_claim('aud', claims) self._check_integer_claim('exp', claims) self._check_integer_claim('nbf', claims) self._check_integer_claim('iat', claims) self._check_string_claim('jti', claims) if self._check_claims is None: if 'exp' in claims: self._check_exp(claims['exp'], time.time(), self._leeway) if 'nbf' in claims: self._check_exp(claims['nbf'], time.time(), self._leeway) def _check_provided_claims(self): # check_claims can be set to False to skip any check if self._check_claims is False: return try: claims = json_decode(self.claims) if not isinstance(claims, dict): raise ValueError() except ValueError: if self._check_claims is not None: raise JWTInvalidClaimFormat( "Claims check requested but claims is not a json dict") return self._check_default_claims(claims) if self._check_claims is None: return for name, value in self._check_claims.items(): if name not in claims: raise JWTMissingClaim("Claim %s is missing" % (name, )) if name in ['iss', 'sub', 'jti']: if value is not None and value != claims[name]: raise JWTInvalidClaimValue( "Invalid '%s' value. Expected '%s' got '%s'" % ( name, value, claims[name])) elif name == 'aud': if value is not None: if value == claims[name]: continue if isinstance(claims[name], list): if value in claims[name]: continue raise JWTInvalidClaimValue( "Invalid '%s' value. Expected '%s' in '%s'" % ( name, value, claims[name])) elif name == 'exp': if value is not None: self._check_exp(claims[name], value, 0) else: self._check_exp(claims[name], time.time(), self._leeway) elif name == 'nbf': if value is not None: self._check_nbf(claims[name], value, 0) else: self._check_nbf(claims[name], time.time(), self._leeway) else: if value is not None and value != claims[name]: raise JWTInvalidClaimValue( "Invalid '%s' value. Expected '%d' got '%d'" % ( name, value, claims[name])) def make_signed_token(self, key): """Signs the payload. Creates a JWS token with the header as the JWS protected header and the claims as the payload. See (:class:`jwcrypto.jws.JWS`) for details on the exceptions that may be reaised. :param key: A (:class:`jwcrypto.jwk.JWK`) key. """ t = JWS(self.claims) t.add_signature(key, protected=self.header) self.token = t def make_encrypted_token(self, key): """Encrypts the payload. Creates a JWE token with the header as the JWE protected header and the claims as the plaintext. See (:class:`jwcrypto.jwe.JWE`) for details on the exceptions that may be reaised. :param key: A (:class:`jwcrypto.jwk.JWK`) key. """ t = JWE(self.claims, self.header) t.add_recipient(key) self.token = t def deserialize(self, jwt, key=None): """Deserialize a JWT token. NOTE: Destroys any current status and tries to import the raw token provided. :param jwt: a 'raw' JWT token. :param key: A (:class:`jwcrypto.jwk.JWK`) verification or decryption key. """ c = jwt.count('.') if c == 2: self.token = JWS() elif c == 4: self.token = JWE() else: raise ValueError("Token format unrecognized") # Apply algs restrictions if any, before performing any operation if self._algs: self.token.allowed_algs = self._algs # now deserialize and also decrypt/verify (or raise) if we # have a key self.token.deserialize(jwt, key) if key is not None: self.header = self.token.jose_header self.claims = self.token.payload.decode('utf-8') self._check_provided_claims() def serialize(self, compact=True): """Serializes the object into a JWS token. :param compact(boolean): must be True. Note: the compact parameter is provided for general compatibility with the serialize() functions of :class:`jwcrypto.jws.JWS` and :class:`jwcrypto.jwe.JWE` so that these objects can all be used interchangeably. However the only valid JWT representtion is the compact representation. """ return self.token.serialize(compact)
class JWT(object): """JSON Web token object This object represent a generic token. """ def __init__(self, header=None, claims=None, jwt=None, key=None, algs=None): """Creates a JWT object. :param header: A dict or a JSON string with the JWT Header data. :param claims: A dict or a string withthe JWT Claims data. :param jwt: a 'raw' JWT token :param key: A (:class:`jwcrypto.jwk.JWK`) key to deserialize the token. :param algs: An optional list of allowed algorithms Note: either the header,claims or jwt,key parameters should be provided as a deserialization operation (which occurs if the jwt is provided will wipe any header os claim provided by setting those obtained from the deserialization of the jwt token. """ self._header = None self._claims = None self._token = None self._algs = algs if header: self.header = header if claims: self.claims = claims if jwt is not None: self.deserialize(jwt, key) @property def header(self): if self._header is None: raise KeyError("'header' not set") return self._header @header.setter def header(self, h): if isinstance(h, dict): self._header = json_encode(h) else: self._header = h @property def claims(self): if self._claims is None: raise KeyError("'claims' not set") return self._claims @claims.setter def claims(self, c): if isinstance(c, dict): self._claims = json_encode(c) else: self._claims = c @property def token(self): return self._token @token.setter def token(self, t): if isinstance(t, JWS) or isinstance(t, JWE) or isinstance(t, JWT): self._token = t else: raise TypeError("Invalid token type, must be one of JWS,JWE,JWT") def make_signed_token(self, key): """Signs the payload. Creates a JWS token with the header as the JWS protected header and the claims as the payload. See (:class:`jwcrypto.jws.JWS`) for details on the exceptions that may be reaised. :param key: A (:class:`jwcrypto.jwk.JWK`) key. """ t = JWS(self.claims) t.add_signature(key, protected=self.header) self.token = t def make_encrypted_token(self, key): """Encrypts the payload. Creates a JWE token with the header as the JWE protected header and the claims as the plaintext. See (:class:`jwcrypto.jwe.JWE`) for details on the exceptions that may be reaised. :param key: A (:class:`jwcrypto.jwk.JWK`) key. """ t = JWE(self.claims, self.header) t.add_recipient(key) self.token = t def deserialize(self, jwt, key=None): """Deserialize a JWT token. NOTE: Destroys any current status and tries to import the raw token provided. :param jwt: a 'raw' JWT token. :param key: A (:class:`jwcrypto.jwk.JWK`) verification or decryption key. """ c = jwt.count('.') if c == 2: self.token = JWS() elif c == 4: self.token = JWE() else: raise ValueError("Token format unrecognized") # Apply algs restrictions if any, before performing any operation if self._algs: self.token.allowed_algs = self._algs # now deserialize and also decrypt/verify (or raise) if we # have a key self.token.deserialize(jwt, key) if key is not None: self.header = self.token.jose_header self.claims = self.token.payload.decode('utf-8') def serialize(self, compact=True): """Serializes the object into a JWS token. :param compact(boolean): must be True. Note: the compact parameter is provided for general compatibility with the serialize() functions of :class:`jwcrypto.jws.JWS` and :class:`jwcrypto.jwe.JWE` so that these objects can all be used interchangeably. However the only valid JWT representtion is the compact representation. """ return self.token.serialize(compact)