def testNoCreds(self): """authenticate() a user with no creds""" user = Prototype() user.username = '******' user.nonce = 'y' user.nextnonce = 'z' def callback(u): assert False, 'Callback called in MISSING_CREDS' user = pychap.authenticate(callback, user) # nonce self.assertEqual(user.nonce, 'y') #nextnonce self.assertEqual(user.nextnonce, 'z') #passkey self.assertEqual(getattr(user, 'passkey', None), None) #authenticated self.assertEqual(user.authenticated, False) #authmessage self.assertEqual(user.message, pychap.MISSING_CREDS)
def testPasskey(self): """user is not authenticated""" user = Prototype() user.username = '******' user.nonce = 'x' user.nextnonce = 'x' user.cnonce = 'x' user.response = 'x' user.passkey = 'x' def callback(u): assert False, 'Callback called in MISSING_CREDS' user = pychap.authenticate(callback, user) # nonce self.assertEqual(user.nonce, 'x') #nextnonce self.assertEqual(user.nextnonce, 'x') #passkey self.assertEqual(user.passkey, 'x') #authenticated self.assertEqual(user.authenticated, False) #authmessage self.assertEqual(user.message, pychap.DENIED)
def testWithoutModifiedPasskey(self): """authenticate() a user without a modified passkey""" nonce = 'a_nonce' nextnonce = 'a_nextnonce' response = hashlib.sha1(nonce).hexdigest() cnonce = hashlib.sha1( hashlib.sha1(nextnonce).hexdigest()).hexdigest() user = Prototype() user.username = '******' user.nonce = nonce user.nextnonce = nextnonce user.cnonce = cnonce user.response = response user.passkey = 'y' def callback(u): assert False, 'Callback called in MISSING_CREDS' user = pychap.authenticate(callback, user) # nonce self.assertEqual(user.nonce, nonce) #nextnonce self.assertEqual(user.nextnonce, nextnonce) #passkey self.assertEqual(user.passkey, 'y') #authenticated self.assertEqual(user.authenticated, False) #authmessage self.assertEqual(user.message, pychap.UNMODIFIED)
def d3_put(self, request, credentials, match): # A call to the "/users/" URL without a username is pointless. if not match: # match could be '' self.message_out(501, 'The URL \\"/users/\\" is not implemented on this host.') return target_user = BaseUser.get(match) if target_user is None: # If the user does not exist, we assume the caller intended to create a new # one. target_user = BaseUser(match) new_user = pychap.authenticate(store.put_user, target_user) return self.out(status=201, message='Created.', creds=new_user.credentials, body={'username': new_user.username}) # Otherwise we assume the caller is trying to update this user's data, so we # try to authenticate. creds = authenticate(credentials) auth_user = BaseUser.get(creds[0]) # It is wrong to assume that we are existing in a magic pony land where all # the planets line up prefectly and our programs are bug free. In this # case, if we don't make this seemingly meaningless assigment of one user # object to another, then when a user updates their own data, really bad # shit happens to our authentication scheme. if target_user.username == auth_user.username: target_user = auth_user # The first thing we need to do is check to see if the caller is trying to # update the permission level group membership. new_groups = request.get('groups') if new_groups != target_user.groups and isinstance(new_groups, list): # Define a function to use with the builtin 'reduce()' to determine the # permission level of the calling user. def reduce_level(current_level, group): if groups.MAP[group] > current_level: current_level = groups.MAP[group] return current_level level = reduce(reduce_level, auth_user.groups, 0) # Once we have the permission level of the calling user, we can then check # all of the modifications they have indicated that they want to make. for g in new_groups: if g in target_user.groups: continue # The user already belongs to this group. group_level = groups.MAP.get(g) if group_level is None: continue # The group does not exist. if group_level > level: continue # The user does not have permission for this group. # Else add the user to the group. target_user.groups.append(g) target_user.put() self.out(status=200, message='Updated.', creds=creds, body={'username': target_user.username, 'groups': target_user.groups})
def testNewUser(self): """authenticate() a new user (no nonce or nextnonce)""" user = Prototype() user.someother = 1 user.username = '******' self.assertEqual( pychap.authenticate(self.callback, user), self.user)
def testSetPasskey(self): """authenticate() a user with no passkey""" user = Prototype() user.username = '******' user.nonce = 'a' user.nextnonce = 'b' user.cnonce = 'c' user.response = 'd' self.assertEqual(pychap.authenticate(self.callback, user), self.user)
def main(): TEMP_TEST_USERNAME = '******' http_method = os.environ['REQUEST_METHOD'] if http_method == 'GET': respond('200 OK', TEMP_TEST_USERNAME) return # Check to see if we are on the local dev_appserver. # If not, we bail! if not os.environ['SERVER_SOFTWARE'].startswith('Development'): respond('403 Forbidden','') return logging.critical('/testsetup has been accessed') import store user = store.BaseUser.get(TEMP_TEST_USERNAME) if http_method == 'PUT': if user is None: user = store.BaseUser(TEMP_TEST_USERNAME) user.groups = [ 'users', 'sys_admin', 'user_admin', 'account_admin', 'database'] import pychap pychap.authenticate(store.put_user, user) respond('200 OK', TEMP_TEST_USERNAME) elif http_method == 'DELETE': if user is not None: user.delete() respond('204 No Content', '') else: respond('405 Method Not Allowed','')
def testNewUser(self): """user authenticates""" user = Prototype() user.username = u'a' user.nonce = u'b' user.nextnonce = u'c' user.cnonce = u'd' user.response = u'e' user.passkey = u'58e6b3a414a1e090dfc6029add0f3555ccba127f' self.assertEqual( pychap.authenticate(self.callback, user), self.user)
def testInvalidPasskey(self): """invalid passkey""" user = Prototype() user.username = '******' user.nonce = 'x' user.nextnonce = 'x' user.cnonce = 'x' user.response = 'x' user.passkey = [] def callback(u): assert False, 'Callback called in MISSING_CREDS' ex = False try: user = pychap.authenticate(callback, user) except AssertionError, ae: ex = ae
def testInvalidParams(self): """Invalid Params.""" ex = False try: pychap.authenticate(None) except TypeError: ex = True assert ex, 'params (None) raises exception.' ex = False try: pychap.authenticate((lambda : None)) except TypeError: ex = True assert ex, 'params (lambda, None) raises exception.' ex = False try: pychap.authenticate((lambda : None), 1) except AssertionError: ex = True assert ex, 'params (lambda, 1) raises exception.' user = Prototype() user.nonce = 4 ex = False try: pychap.authenticate((lambda : None), user) except AssertionError: ex = True assert ex, 'params (lambda, "", 4) raises exception.' user = Prototype() user.username = '******' user.nonce = 4 ex = False try: pychap.authenticate((lambda : None), user) except AssertionError: ex = True assert ex, 'params (lambda, "", 4) raises exception.' user = Prototype() user.username = '******' user.nonce = '' user.nextnonce = 99 ex = False try: pychap.authenticate((lambda : None), user) except AssertionError: ex = True assert ex, 'params (lambda, "", "", "") raises exception.' user = Prototype() user.username = '******' user.nonce = 'x' user.nextnonce = 'x' user.cnonce = 1 ex = False try: pychap.authenticate((lambda : None), user) except AssertionError: ex = True assert ex, 'params (lambda, "", "", False) raises exception.' user = Prototype() user.username = '******' user.nonce = 'x' user.nextnonce = 'x' user.cnonce = 'x' user.response = [1] ex = False try: pychap.authenticate((lambda : None), user) except AssertionError: ex = True assert ex, 'params (lambda, []) raises exception.'
def authenticate(creds): """Take the CHAP credentials of a user and try to authenticate. Args: creds: A list of credentials: username, cnonce, response Returns: A list of username, nonce, and nextnonce if the user authenticates. Raises: AuthenticationError: If the credentials are invalid. Authenticate: If the credentials are incomplete or the response does not match the stored passkey. """ # If the DCube head dictionary does not have an 'authorization' entry, then # we asign it an empty list by default. This is to prevent bugs later in # the program where a list object is expected. creds = creds or [] # Make sure the credentials object is a list with more than 1 entry. If we # don't even have a single item in the credentials list, there is nothing # more we can do besides return a relevant DCube message. if not isinstance(creds, list) or len(creds) is 0: raise AuthenticationError('No authorization credentials.') # auth[0] should be the username. If it is not a string, the caller sent an # invalid username in the request and we respond with a relevant DCube # message. if not isinstance(creds[0], basestring): raise AuthenticationError('Username \\"%s\\" is invalid.'% (creds[0] is None and 'null' or str(creds[0]))) username = creds[0] # Get the user from the datastore. user = BaseUser.get(username) if user is None: # The user does not exist. raise AuthenticationError('Username \\"%s\\" does not exist.'% username) # If the user exists there is no reason it should not have the nonce and # nextnonce attributes. assert user.nonce, ('%s user.nonce is expected to exist! (%s)'% (username, user.nonce)) assert user.nextnonce, ('%s user.nextnonce is expected to exist! (%s)'% (username, user.nextnonce)) user.cnonce = None user.response = None if len(creds) == 3: # If the user sent the cnonce and response, we need to check those too. # auth[1] should be the cnonce and auth[2] should be the response. Both the # cnonce and response must be strings. If not, we send back the relevant # message for the response. if not isinstance(creds[1], basestring): raise AuthenticationError('The given cnonce \\"%s\\" is invalid.'% (creds[1] is None and 'null' or str(creds[1]))) if not isinstance(creds[2], basestring): raise AuthenticationError('The given response \\"%s\\" is invalid.'% (creds[2] is None and 'null' or str(creds[2]))) user.cnonce = creds[1] user.response = creds[2] # Use the pychap module to authenticate. If the users credentials are # updated by pychap it will call store.put(). This process ensures that the # new CHAP credentials are persisted to disk and ready for the next request # made by this user. auth_user = pychap.authenticate(store.put_user, user) # DEBUG logging.warn('Auth message: %s', auth_user.message) if not auth_user.authenticated: # The user did not authenticate, so we return the relevant output message. raise Authenticate( user.username, auth_user.nonce, auth_user.nextnonce) # If we made it this far, then everything has gone OK and we return the user # credentials.. return [auth_user.username, auth_user.nonce, auth_user.nextnonce]