diff --git a/auth.py b/auth.py index b768d651..08b396ef 100644 --- a/auth.py +++ b/auth.py @@ -49,25 +49,50 @@ def nicknameFromBasicAuth(authHeader: str) -> str: return None return plain.split(':')[0] -def authorizeBasic(baseDir: str,authHeader: str) -> bool: +def authorizeBasic(baseDir: str,path: str,authHeader: str,debug: bool) -> bool: """HTTP basic auth """ if ' ' not in authHeader: + if debug: + print('DEBUG: Authorixation header does not contain a space character') return False + if '/users/' not in path: + if debug: + print('DEBUG: Path for Authorization does not contain a user') + return False + pathUsersSection=path.split('/users/')[1] + if '/' not in pathUsersSection: + if debug: + print('DEBUG: This is not a users endpoint') + return False + nicknameFromPath=pathUsersSection.split('/')[0] base64Str = authHeader.split(' ')[1].replace('\n','') plain = base64.b64decode(base64Str).decode('utf-8') if ':' not in plain: + if debug: + print('DEBUG: Basic Auth header does not contain a ":" separator for username:password') return False nickname = plain.split(':')[0] + if nickname!=nicknameFromPath: + if debug: + print('DEBUG: Nickname given in the path ('+nicknameFromPath+') does not match the one in the Authorization header ('+nickname+')') + return False passwordFile=baseDir+'/accounts/passwords' if not os.path.isfile(passwordFile): + if debug: + print('DEBUG: passwords file missing') return False providedPassword = plain.split(':')[1] passfile = open(passwordFile, "r") for line in passfile: if line.startswith(nickname+':'): storedPassword=line.split(':')[1].replace('\n','') - return verifyPassword(storedPassword,providedPassword) + success = verifyPassword(storedPassword,providedPassword) + if not success: + if debug: + print('DEBUG: Password check failed for '+nickname) + return success + print('DEBUG: Did not find credentials for '+nickname+' in '+passwordFile) return False def storeBasicCredentials(baseDir: str,nickname: str,password: str) -> bool: @@ -100,7 +125,7 @@ def storeBasicCredentials(baseDir: str,nickname: str,password: str) -> bool: passfile.write(storeStr+'\n') return True -def authorize(baseDir: str,authHeader: str) -> bool: +def authorize(baseDir: str,path: str,authHeader: str,debug: bool) -> bool: if authHeader.lower().startswith('basic '): - return authorizeBasic(baseDir,authHeader) + return authorizeBasic(baseDir,path,authHeader,debug) return False diff --git a/daemon.py b/daemon.py index 75a04b4f..98c1a73b 100644 --- a/daemon.py +++ b/daemon.py @@ -172,15 +172,18 @@ class PubServer(BaseHTTPRequestHandler): if self.path.endswith('/inbox'): if '/users/' in self.path: if self.headers.get('Authorization'): - nickname=self.path.split('/users/')[1].replace('/inbox','') - if nickname==nicknameFromBasicAuth(self.headers['Authorization']): - if authorize(self.server.baseDir,self.headers['Authorization']): - # TODO - print('inbox access not supported yet') - self.send_response(405) - self.end_headers() - self.server.POSTbusy=False - return + if authorize(self.server.baseDir,self.path,self.headers['Authorization'],self.server.debug): + # TODO + print('inbox access not supported yet') + self.send_response(405) + self.end_headers() + self.server.POSTbusy=False + return + else: + if self.server.debug: + print('DEBUG: '+nickname+' was not authorized to access '+self.path) + if self.server.debug: + print('DEBUG: GET access to inbox is unauthorized') self.send_response(405) self.end_headers() self.server.POSTbusy=False diff --git a/person.py b/person.py index d0c60788..e4b9cd24 100644 --- a/person.py +++ b/person.py @@ -52,7 +52,7 @@ def createPerson(baseDir: str,nickname: str,domain: str,port: int, \ 'value': 'schema:value'}], 'attachment': [], 'endpoints': { - 'id': httpPrefix+'://'+domain+'/users/'+nickname+'/endpoints' + 'id': httpPrefix+'://'+domain+'/users/'+nickname+'/endpoints', 'sharedInbox': httpPrefix+'://'+domain+'/inbox', 'uploadMedia': httpPrefix+'://'+domain+'/users/'+nickname+'/endpoints/uploadMedia' }, diff --git a/posts.py b/posts.py index 11ddb968..6309c502 100644 --- a/posts.py +++ b/posts.py @@ -360,7 +360,7 @@ def createPostBase(baseDir: str,nickname: str, domain: str, port: int, \ savePostToOutbox(baseDir,httpPrefix,newPostId,nickname,domain,newPost) return newPost -def outboxMessageCreateWrap(httpPrefix str,nickname: str,domain: str,messageJson: {}) -> {}: +def outboxMessageCreateWrap(httpPrefix: str,nickname: str,domain: str,messageJson: {}) -> {}: """Wraps a received message in a Create https://www.w3.org/TR/activitypub/#object-without-create """ diff --git a/tests.py b/tests.py index b2e28779..2ddc53d7 100644 --- a/tests.py +++ b/tests.py @@ -318,16 +318,18 @@ def testAuthentication(): authHeader=createBasicAuthHeader(nickname,password) assert nickname==nicknameFromBasicAuth(authHeader) - assert authorizeBasic(baseDir,authHeader) + assert authorizeBasic(baseDir,'/users/'+nickname+'/inbox',authHeader,False) + assert authorizeBasic(baseDir,'/users/'+nickname,authHeader,False)==False + assert authorizeBasic(baseDir,'/users/othernick/inbox',authHeader,False)==False authHeader=createBasicAuthHeader(nickname,password+'1') - assert authorizeBasic(baseDir,authHeader)==False + assert authorizeBasic(baseDir,'/users/'+nickname+'/inbox',authHeader,False)==False password='someOtherPassword' assert storeBasicCredentials(baseDir,nickname,password) authHeader=createBasicAuthHeader(nickname,password) - assert authorizeBasic(baseDir,authHeader) + assert authorizeBasic(baseDir,'/users/'+nickname+'/inbox',authHeader,False) os.chdir(currDir) shutil.rmtree(baseDir)