소스 검색

modified the server so, that it not only works with passwords but with usernames and multiple users with different passwords

the client is now more interactive and allows the user to decide which 
endpoint to call

update architecure in README.md
master
DragonSkills99 5 년 전
부모
커밋
6da0f5ea12
3개의 변경된 파일99개의 추가작업 그리고 21개의 파일을 삭제
  1. 24
    8
      README.md
  2. 48
    7
      chap-client.py
  3. 27
    6
      chap-server.py

+ 24
- 8
README.md 파일 보기

@@ -4,12 +4,25 @@ This are two little python scripts to demonstrate the CHAP workflow. One script

##Presets

- Python 3
- Python 3.8.5

##Usage

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

The server script will the serve a XMLRPC server with 4 endpoints on Port 8000 at localhost (the local machine) :
@@ -17,18 +30,21 @@ The server script will the serve a XMLRPC server with 4 endpoints on Port 8000 a
- init(): [ *session_id*: *uuid*, *seed*: *uuid* ]

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

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.

+ 48
- 7
chap-client.py 파일 보기

@@ -2,16 +2,57 @@

import xmlrpc.client
import hashlib
import os
import sys

# connects to the XMLRPC Server
s = xmlrpc.client.ServerProxy('http://localhost:8000')
clear = lambda: os.system('clear')
# initalized the login process
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

+ 27
- 6
chap-server.py 파일 보기

@@ -1,6 +1,7 @@
#!/usr/bin/env python2

import uuid
import pickle
import hashlib
from xmlrpc.server import SimpleXMLRPCServer
from xmlrpc.server import SimpleXMLRPCRequestHandler
@@ -14,15 +15,35 @@ server = SimpleXMLRPCServer(("localhost", 8000),
requestHandler=RequestHandler)
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
# published as XML-RPC methods
class CHAP:
test_password = 'Test123'
# initializes class-instance and instance variables
# if no userdata exists, it creates a default user
def __init__( self ):
self.keys = {}
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
# and send the generated random salt
@@ -37,9 +58,9 @@ class CHAP:

# checks if send hash is same as internally generated to validate if the correct
# 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()
self.authenticated[ session ] = passhash == password_hash
return self.authenticated[ session ] == True
@@ -48,8 +69,8 @@ class CHAP:

# adds functionality for users to log them selfes off, but also need the
# 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.keys[ session ]
return self.authenticated.get( session ) != True

Loading…
취소
저장