the client is now more interactive and allows the user to decide which endpoint to call update architecure in README.mdmaster
| ##Presets | ##Presets | ||||
| - Python 3 | |||||
| - Python 3.8.5 | |||||
| ##Usage | ##Usage | ||||
| To use just first start the server and then the client script | To use just first start the server and then the client script | ||||
| ## Imported Libraries | |||||
| ### Client | |||||
| - xmlrpc.client | |||||
| - hashlib | |||||
| - os | |||||
| - sys | |||||
| ## Server | |||||
| - uuid | |||||
| - pickle | |||||
| - hashlib | |||||
| - xmlrpc.server | |||||
| ##Internal workings | ##Internal workings | ||||
| The server script will the serve a XMLRPC server with 4 endpoints on Port 8000 at localhost (the local machine) : | The server script will the serve a XMLRPC server with 4 endpoints on Port 8000 at localhost (the local machine) : | ||||
| - init(): [ *session_id*: *uuid*, *seed*: *uuid* ] | - init(): [ *session_id*: *uuid*, *seed*: *uuid* ] | ||||
| This endpoint will start a new session and send you the id and seed of this new session | This endpoint will start a new session and send you the id and seed of this new session | ||||
| - auth( *session_id*: *uuid*, *password_hash*: *string*): *bool* | |||||
| - auth( *session_id*: *uuid*, *username*: *string*, *password_hash*: *string*): *bool* | |||||
| This endpoint requires the session id and your password hash generated from the password concatenated with the seed and hashed using sha256 | |||||
| This endpoint requires the session id, an username and your password hash generated from the password concatenated with the seed and hashed using sha256 | |||||
| It will return whether the password is correct and you are authorized and set you as authorized in the server instance | It will return whether the password is correct and you are authorized and set you as authorized in the server instance | ||||
| - logout( *session_id*: *uuid*, *password_hash*: *string*): *bool* | |||||
| - logout( *session_id*: *uuid*, *username*: *string*, *password_hash*: *string*): *bool* | |||||
| This endpoint requires the session id and your password hash generated from the password concatenated with the seed and hashed using sha256 | |||||
| It will destroy the session and return you if it worked (should always return true) | |||||
| - hello(): *string* | |||||
| This endpoint requires the session id, an username and your password hash generated from the password concatenated with the seed and hashed using sha256 | |||||
| It will destroy the session and return you if it worked (should always return true) | |||||
| - hello( *session_id*: *uuid* ): *string* | |||||
| This endpoint will return a string with a hello message if you are authorized and a denial message otherwise | This endpoint will return a string with a hello message if you are authorized and a denial message otherwise | ||||
| - create_user( *session*: *uuid*, *username*: *string*, *password*: *string* ) | |||||
| This endpoint requires the session id a username and a password for a user to add, adds this user and saves it to a file | |||||
| Note: *uuid* is not a the DataType but a string in uuid format | Note: *uuid* is not a the DataType but a string in uuid format | ||||
| The client script will then establish a connection, initialize a session, successfully authorize itself, print the return value from hello method and finally destroy the session. | |||||
| The client script will then establish a connection, initialize a session, successfully authorize itself, print the return value from hello method and finally destroy the session. |
| import xmlrpc.client | import xmlrpc.client | ||||
| import hashlib | import hashlib | ||||
| import os | |||||
| import sys | |||||
| # connects to the XMLRPC Server | # connects to the XMLRPC Server | ||||
| s = xmlrpc.client.ServerProxy('http://localhost:8000') | s = xmlrpc.client.ServerProxy('http://localhost:8000') | ||||
| clear = lambda: os.system('clear') | |||||
| # initalized the login process | # initalized the login process | ||||
| session, key = s.init() | session, key = s.init() | ||||
| password_hash = hashlib.sha256( ( 'Test123' + key ).encode( 'utf-8' ) ).hexdigest(); | |||||
| authenticated = False | |||||
| username = '' | |||||
| password = '' | |||||
| # does the actual authentication | |||||
| print( s.auth( session, password_hash ) ) | |||||
| # tests protected method | |||||
| print( s.hello( session ) ) | |||||
| # logs out cause anything seems to be done already | |||||
| print( s.logout( session, password_hash ) ) | |||||
| # concatenates the password and key and returns the hash | |||||
| def hash_pass( password, key ): | |||||
| return hashlib.sha256( ( password + key ).encode( 'utf-8' ) ).hexdigest() | |||||
| # starts main loop | |||||
| while True: | |||||
| clear() | |||||
| # if authenticated offer to user premium methods | |||||
| if authenticated: | |||||
| print( 'Welcome ' + username ) | |||||
| print( 'Please enter what you want to do ( hello, create_user, logout )' ) | |||||
| i = input().lower() | |||||
| clear() | |||||
| if ( i == 'hello' ): | |||||
| print( s.hello( session ) ) | |||||
| elif ( i == 'create_user' ): | |||||
| print( 'Username: ' ) | |||||
| un = input() | |||||
| clear() | |||||
| print( 'Password:' ) | |||||
| pw = input() | |||||
| clear() | |||||
| print( s.create_user( session, un, pw ) ) | |||||
| elif( i == 'logout' or i == 'exit' ): | |||||
| if ( s.logout( session, username, hash_pass( password, key ) ) ): | |||||
| authenticated = False | |||||
| sys.exit() | |||||
| else: | |||||
| print( 'Unknown action ' + i ) | |||||
| print( 'Press any key to continue' ) | |||||
| input(); | |||||
| # otherwise offer to authenticate | |||||
| else: | |||||
| print( 'Username: ' ) | |||||
| username = input() | |||||
| clear() | |||||
| print( 'Password:' ) | |||||
| password = input() | |||||
| clear() | |||||
| authenticated = s.auth( session, username, hash_pass( password, key ) ) | |||||
| pass |
| #!/usr/bin/env python2 | #!/usr/bin/env python2 | ||||
| import uuid | import uuid | ||||
| import pickle | |||||
| import hashlib | import hashlib | ||||
| from xmlrpc.server import SimpleXMLRPCServer | from xmlrpc.server import SimpleXMLRPCServer | ||||
| from xmlrpc.server import SimpleXMLRPCRequestHandler | from xmlrpc.server import SimpleXMLRPCRequestHandler | ||||
| requestHandler=RequestHandler) | requestHandler=RequestHandler) | ||||
| server.register_introspection_functions() | server.register_introspection_functions() | ||||
| def save_users( users ): | |||||
| pickle.dump( users, open( 'users.data', 'wb' ) ) | |||||
| # Register an instance; all the methods of the instance are | # Register an instance; all the methods of the instance are | ||||
| # published as XML-RPC methods | # published as XML-RPC methods | ||||
| class CHAP: | class CHAP: | ||||
| test_password = 'Test123' | |||||
| # initializes class-instance and instance variables | # initializes class-instance and instance variables | ||||
| # if no userdata exists, it creates a default user | |||||
| def __init__( self ): | def __init__( self ): | ||||
| self.keys = {} | self.keys = {} | ||||
| self.authenticated = {} | self.authenticated = {} | ||||
| try: | |||||
| self.users = pickle.load( open( 'users.data', 'rb' ) ) | |||||
| except FileNotFoundError: | |||||
| self.users = { 'admin': 'Pass123' } | |||||
| save_users( self.users ) | |||||
| # adds a user to dictionary and saves it to a file | |||||
| # won't be executable if not authorized or if user already exists | |||||
| def create_user( self, session, username, password ): | |||||
| if ( self.authenticated.get( session ) == True ): | |||||
| if not username in self.users: | |||||
| self.users[ username ] = password | |||||
| save_users( self.users ) | |||||
| return 'Created user successfully' | |||||
| else: | |||||
| return 'User already exists' | |||||
| else: | |||||
| return 'Sorry, please authenticate first' | |||||
| # tells the server to start the autentification process | # tells the server to start the autentification process | ||||
| # and send the generated random salt | # and send the generated random salt | ||||
| # checks if send hash is same as internally generated to validate if the correct | # checks if send hash is same as internally generated to validate if the correct | ||||
| # password was used | # password was used | ||||
| def auth( self, session, password_hash ): | |||||
| if session in self.keys: | |||||
| combined = CHAP.test_password + self.keys[ session ] | |||||
| def auth( self, session, username, password_hash ): | |||||
| if session in self.keys and username in self.users: | |||||
| combined = self.users.get( username ) + self.keys.get( session ) | |||||
| passhash = hashlib.sha256( combined.encode( 'utf-8' ) ).hexdigest() | passhash = hashlib.sha256( combined.encode( 'utf-8' ) ).hexdigest() | ||||
| self.authenticated[ session ] = passhash == password_hash | self.authenticated[ session ] = passhash == password_hash | ||||
| return self.authenticated[ session ] == True | return self.authenticated[ session ] == True | ||||
| # adds functionality for users to log them selfes off, but also need the | # adds functionality for users to log them selfes off, but also need the | ||||
| # the password_hash to ensure, that nobody else logs you off | # the password_hash to ensure, that nobody else logs you off | ||||
| def logout( self, session, password_hash ): | |||||
| if self.auth( session, password_hash ): | |||||
| def logout( self, session, username, password_hash ): | |||||
| if self.auth( session, username, password_hash ): | |||||
| del self.authenticated[ session ] | del self.authenticated[ session ] | ||||
| del self.keys[ session ] | del self.keys[ session ] | ||||
| return self.authenticated.get( session ) != True | return self.authenticated.get( session ) != True |