예제 #1
0
    def setUp(self):
        debug = False
        datadir = pkg_resources.resource_filename(__name__, 'data')
        self.config_file = os.path.join(datadir, 'test_config.ini')
        self.config = vccs_auth.config.VCCSAuthConfig(self.config_file, debug)
        self.credstore = FakeCredentialStore()
        self.kdf = ndnkdf.NDNKDF(self.config.nettle_path)
        self.keys = {
            0x2000: str('2000' * 16).decode('hex'),
            0x2001: str('2001' * 16).decode('hex'),
        }
        self.hasher = vccs_auth.hasher.VCCSSoftHasher(
            self.keys, vccs_auth.hasher.NoOpLock())
        self.logger = VCCSLogger('test_authbackend', syslog=False)

        #cherrypy.root = AuthBackend(self.hasher, self.kdf, self.logger, self.credstore, self.config)

        self.authbackend = AuthBackend(self.hasher,
                                       self.kdf,
                                       self.logger,
                                       self.credstore,
                                       self.config,
                                       expose_real_errors=True)
        cherrypy.tree.mount(self.authbackend, '/')
        cherrypy.engine.start()

        self.bcrypt_salt1 = '$2a$08$Ahy51oCM6Vg6d.1ScOPxse'
예제 #2
0
 def setUp(self):
     debug = False
     datadir = pkg_resources.resource_filename(__name__, 'data')
     self.config_file = os.path.join(datadir, 'test_config.ini')
     self.config = vccs_auth.config.VCCSAuthConfig(self.config_file, debug)
     self.credstore = FakeCredentialStore()
     self.kdf = ndnkdf.NDNKDF(self.config.nettle_path)
     self.keys = {
         0x2000: str('2000' * 16).decode('hex'),
     }
     self.hasher = vccs_auth.hasher.VCCSSoftHasher(
         self.keys, vccs_auth.hasher.NoOpLock())
     self.logger = VCCSLogger('test_authbackend', self.config)
예제 #3
0
파일: test_oath.py 프로젝트: SUNET/VCCS
    def setUp(self):
        debug = False
        datadir = pkg_resources.resource_filename(__name__, 'data')
        self.config_file = os.path.join(datadir, 'test_config.ini')
        self.config = vccs_auth.config.VCCSAuthConfig(self.config_file, debug)
        self.key_handle = 0x2001
        self.keys = {self.key_handle: str('2001' * 16).decode('hex'),
                     }
        self.hasher = vccs_auth.hasher.VCCSSoftHasher(self.keys, vccs_auth.hasher.NoOpLock())
        self.logger = FakeLogger()
        self.credstore = FakeCredentialStore(creds={})

        self.test_key = '3132333435363738393031323334353637383930'.decode('hex')
        self.nonce = '010203040506'.decode('hex')
        flags = struct.pack('< I', pyhsm.defines.YSM_HMAC_SHA1_GENERATE)
        self.aead = pyhsm.soft_hsm.aesCCM(self.keys[self.key_handle], self.key_handle, self.nonce,
                                          self.test_key + flags, decrypt = False)
        print "Generated AEAD {!r}".format(self.aead.encode('hex'))
예제 #4
0
    def setUp(self):
        debug = False
        datadir = pkg_resources.resource_filename(__name__, 'data')
        self.config_file = os.path.join(datadir, 'test_config.ini')
        self.config = vccs_auth.config.VCCSAuthConfig(self.config_file, debug)
        self.credstore = FakeCredentialStore()
        self.kdf = ndnkdf.NDNKDF(self.config.nettle_path)
        self.keys = {0x2000: str('2000' * 16).decode('hex'),
                     0x2001: str('2001' * 16).decode('hex'),
                     }
        self.hasher = vccs_auth.hasher.VCCSSoftHasher(self.keys, vccs_auth.hasher.NoOpLock())
        self.logger = VCCSLogger('test_authbackend', self.config)

        #cherrypy.root = AuthBackend(self.hasher, self.kdf, self.logger, self.credstore, self.config)

        self.authbackend = AuthBackend(self.hasher, self.kdf, self.logger, self.credstore,
                                       self.config, expose_real_errors = True)
        cherrypy.tree.mount(self.authbackend, '/')
        cherrypy.engine.start()

        self.bcrypt_salt1 = '$2a$08$Ahy51oCM6Vg6d.1ScOPxse'
예제 #5
0
class TestAuthBackend(cptestcase.BaseCherryPyTestCase):
    def setUp(self):
        debug = False
        datadir = pkg_resources.resource_filename(__name__, 'data')
        self.config_file = os.path.join(datadir, 'test_config.ini')
        self.config = vccs_auth.config.VCCSAuthConfig(self.config_file, debug)
        self.credstore = FakeCredentialStore()
        self.kdf = ndnkdf.NDNKDF(self.config.nettle_path)
        self.keys = {0x2000: str('2000' * 16).decode('hex'),
                     0x2001: str('2001' * 16).decode('hex'),
                     }
        self.hasher = vccs_auth.hasher.VCCSSoftHasher(self.keys, vccs_auth.hasher.NoOpLock())
        self.logger = VCCSLogger('test_authbackend', self.config)

        #cherrypy.root = AuthBackend(self.hasher, self.kdf, self.logger, self.credstore, self.config)

        self.authbackend = AuthBackend(self.hasher, self.kdf, self.logger, self.credstore,
                                       self.config, expose_real_errors = True)
        cherrypy.tree.mount(self.authbackend, '/')
        cherrypy.engine.start()

        self.bcrypt_salt1 = '$2a$08$Ahy51oCM6Vg6d.1ScOPxse'

    def tearDown(self):
        cherrypy.engine.exit()

    def _bcrypt_hash(self, plaintext):
        bcrypt_hashed = bcrypt.hashpw(plaintext, self.bcrypt_salt1)
        return bcrypt_hashed[len(self.bcrypt_salt1):]

    def test_bad_request(self):
        """
        Verify bad requests are rejected
        """
        response = self.request('/')
        self.assertEqual(response.output_status, '404 Not Found')

    def test_bad_request2(self):
        """
        Verify bad requests are rejected (right URL, no param)
        """
        response = self.request('/authenticate', return_error = True)
        self.assertIn('Failed parsing request', response.body[0])

    def test_auth_request_wrong_version(self):
        """
        Verify auth request with wrong version is rejected
        """
        a = {'auth': {'version': 9999,
                      'user_id': '*****@*****.**',
                      },
             }
        j = json.dumps(a)
        response = self.request('/authenticate', request = j, return_error = True)
        self.assertIn('Unknown request version : 9999', response.body[0])

        # try again with blinding
        self.authbackend.expose_real_errors = False
        response = self.request('/authenticate', request = j, return_error = True)
        self.assertEqual(response.output_status, '500 Internal Server Error')

    def test_auth_missing_data(self):
        """
        Verify auth request with missing data is rejected
        """
        for req_field in ['version', 'user_id', 'factors']:
            a = {'auth': {'version': 1,
                          'user_id': '*****@*****.**',
                          'factors': [],
                          },
                 }
            del a['auth'][req_field]
            j = json.dumps(a)
            response = self.request('/authenticate', request = j, return_error = True)
            self.assertIn("No '{!s}' in request".format(req_field), response.body[0])

    def test_auth_request1(self):
        """
        Verify correct authentication request
        """
        H1 = self._bcrypt_hash('plaintext')
        a = {'auth': {'version': 1,
                      'user_id': '*****@*****.**',
                      'factors': [
                          {'type': 'password',
                           'H1': H1,
                           'credential_id': '4711',
                           }],
                      },
             }
        j = json.dumps(a)
        response = self.request('/authenticate', request = j, return_error = True)
        res = json.loads(response.body[0])
        expected = {'auth_response': {'version': 1,
                                      'authenticated': True,
                                      },
                    }
        self.assertEqual(res, expected)

    def test_auth_request2(self):
        """
        Verify correct authenticate request with incorrect password
        """
        H1 = self._bcrypt_hash('textplain')
        a = {'auth': {'version': 1,
                      'user_id': '*****@*****.**',
                      'factors': [
                          {'type': 'password',
                           'H1': H1,
                           'credential_id': '4711',
                           }]
                      },
             }
        j = json.dumps(a)
        response = self.request('/authenticate', request = j, return_error = True)
        res = json.loads(response.body[0])
        expected = {'auth_response': {'version': 1,
                                      'authenticated': False,
                                      },
                    }
        self.assertEqual(res, expected)

    def test_auth_request3(self):
        """
        Verify authenticate request without credentials
        """
        a = {'auth': {'version': 1, 'user_id': '*****@*****.**',
                      'factors': [],
                      },
             }
        j = json.dumps(a)
        response = self.request('/authenticate', request = j, return_error = True)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '501 Not Implemented')
        self.assertEqual(response.body, [])

    def test_auth_request4(self):
        """
        Verify authenticate request with imaginary credential type
        """
        a = {'auth': {'version': 1,
                      'user_id': '*****@*****.**',
                      'factors': [{'type': 'promise'}],
                      },
             }
        j = json.dumps(a)
        response = self.request('/authenticate', request = j, return_error = True)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '200 OK')
        res = json.loads(response.body[0])
        expected = {'auth_response': {'version': 1,
                                      'authenticated': False,
                                      },
                    }
        self.assertEqual(res, expected)

    def test_auth_request5(self):
        """
        Verify correct authentication request but with unknown credential
        """
        H1 = self._bcrypt_hash('plaintext')
        cred_id = '9898'
        a = {'auth': {'version': 1,
                      'user_id': '*****@*****.**',
                      'factors': [
                          {'type': 'password',
                           'H1': H1,
                           'credential_id': cred_id,
                           }],
                      },
             }
        j = json.dumps(a)
        response = self.request('/authenticate', request = j, return_error = True)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '500 Internal Server Error')
        self.assertIn('Unknown credential: {!r}'.format(cred_id), response.body[0])


    def test_add_creds_request1(self):
        """
        Verify correct add_credentials password request
        """
        H1 = self._bcrypt_hash('foobar')
        cred_id = '4720'
        a = {'add_creds': {'version': 1,
                           'user_id': '*****@*****.**',
                           'factors': [
                               {'type': 'password',
                                'H1': H1,
                                'credential_id': cred_id,
                                }],
                           },
             }
        j = json.dumps(a)

        # make sure credential does not exist in credstore
        self.assertIsNone(self.credstore.get_credential(cred_id))

        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        res = json.loads(response.body[0])
        expected = {'add_creds_response': {'version': 1,
                                           'success': True,
                                           },
                    }
        self.assertEqual(res, expected)

        cred = self.credstore.get_credential(cred_id)
        print "CRED {!r}".format(cred)
        self.assertEqual(cred.id(), cred_id)
        self.assertEqual(cred.status(), 'active')
        self.assertGreater(cred.iterations(), 20000)

    def test_add_creds_request2(self):
        """
        Verify correct add_credentials OATH request
        """
        key_handle = self.config.add_creds_oath_key_handles_allow[0]
        test_key = str('aa' * 20).decode('hex')
        nonce = '010203040506'.decode('hex')
        flags = struct.pack('< I', pyhsm.defines.YSM_HMAC_SHA1_GENERATE)
        aead = pyhsm.soft_hsm.aesCCM(self.keys[key_handle], key_handle, nonce,
                                     test_key + flags, decrypt = False)
        cred_id = '4740'
        a = {'add_creds': {'version': 1,
                           'user_id': '*****@*****.**',
                           'factors': [{'aead': aead.encode('hex'),
                                       'credential_id': cred_id,
                                       'digits': 6,
                                       'nonce': nonce.encode('hex'),
                                       'key_handle': key_handle,
                                       'oath_counter': 0,
                                       'type': 'oath-hotp',
                                      }],
                           }
             }
        j = json.dumps(a)

        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        res = json.loads(response.body[0])
        expected = {'add_creds_response': {'version': 1,
                                           'success': True,
                                           }
                    }
        self.assertEqual(res, expected)

        cred = self.credstore.get_credential(cred_id)
        print "CRED {!r}".format(cred)
        self.assertEqual(cred.id(), cred_id)
        self.assertEqual(cred.type(), 'oath-hotp')

    def test_add_creds_request3(self):
        """
        Verify add_credentials from wrong source IP
        """
        a = {'add_creds': {'version': 1,
                           'user_id': '*****@*****.**',
                           'factors': [],
                           },
             }
        j = json.dumps(a)

        response = self.request('/add_creds', return_error = True, remote_hp = '127.128.129.130:50001',
                                request = j)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '403 Forbidden')

    def test_add_creds_request3b(self):
        """
        Verify add_credentials OATH request with unknown key handle
        """
        key_handle = self.config.add_creds_oath_key_handles_allow[0]
        test_key = str('aa' * 20).decode('hex')
        nonce = '010203040506'.decode('hex')
        flags = struct.pack('< I', pyhsm.defines.YSM_HMAC_SHA1_GENERATE)
        aead = pyhsm.soft_hsm.aesCCM(self.keys[key_handle], key_handle, nonce,
                                     test_key + flags, decrypt = False)
        cred_id = '4740'
        a = {'add_creds':
                 {'version': 1,
                  'user_id': '*****@*****.**',
                  'factors': [
                      {'aead': aead.encode('hex'),
                       'credential_id': cred_id,
                       'digits': 6,
                       'nonce': nonce.encode('hex'),
                       'key_handle': key_handle + 55,
                       'oath_counter': 0,
                       'type': 'oath-hotp',
                      }],
                  },
             }
        j = json.dumps(a)

        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE1 {!r}: {!r}".format(response.status, response.body)
        self.assertIn('Add OATH credentials key_handle {} not in allowed list'.format(key_handle + 55),
                      response.body[0])
        self.assertEqual(response.output_status, '500 Internal Server Error')

    def test_add_creds_request3c(self):
        """
        Verify add_credentials OATH request with incorrect AEAD
        """
        key_handle = self.config.add_creds_oath_key_handles_allow[0]
        nonce = '010203040506'.decode('hex')
        aead = ('aa' * 32).decode('hex')
        cred_id = '4740'
        a = {'add_creds': {'version': 1,
                           'user_id': '*****@*****.**',
                           'factors': [{'aead': aead.encode('hex'),
                                        'credential_id': cred_id,
                                        'digits': 6,
                                        'nonce': nonce.encode('hex'),
                                        'key_handle': key_handle,
                                        'oath_counter': 0,
                                        'type': 'oath-hotp',
                                        },
                                       ],
                           },
             }
        j = json.dumps(a)

        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE1 {!r}: {!r}".format(response.status, response.body)
        self.assertIn('AEAD integrity check failed', response.body[0])
        self.assertEqual(response.output_status, '500 Internal Server Error')

    def test_add_creds_request4(self):
        """
        Verify correct add_credentials password request with more than one factor

        More than one factor is currently not allowed, as it is not specified how
        error handling would work (one factor succeeds, next does not).
        """
        H1 = self._bcrypt_hash('foobar')
        cred_id = '4750'
        a = {'add_creds': {'version': 1,
                           'user_id': '*****@*****.**',
                           'factors': [{'type': 'password',
                                        'H1': H1,
                                        'credential_id': cred_id,
                                        },
                                       {'type': 'password',
                                        'H1': H1,
                                       'credential_id': 'some-other-string',
                                        },
                                       ],
                           },
             }
        j = json.dumps(a)

        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '501 Not Implemented')

    def test_add_creds_request5(self):
        """
        Test adding credential that already exists
        """
        H1 = self._bcrypt_hash('foobar')
        cred_id = '4711'
        a = {'add_creds': {'version': 1,
                           'user_id': '*****@*****.**',
                           'factors': [{'type': 'password',
                                        'H1': H1,
                                        'credential_id': cred_id,
                                        },
                                       ],
                           },
             }
        j = json.dumps(a)

        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE1 {!r}: {!r}".format(response.status, response.body)
        self.assertIn('Test already have credential with id {!r}'.format(cred_id), response.body[0])
        self.assertEqual(response.output_status, '500 Internal Server Error')

        # try again with blinding
        self.authbackend.expose_real_errors = False
        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE2 {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '500 Internal Server Error')
        self.assertEqual(response.body, [])


    def test_revoke_creds_request1(self):
        """
        Verify correct revoke_creds request
        """
        H1 = self._bcrypt_hash('foobar')
        cred_id = '4721'
        a = {'add_creds': {'version': 1,
                           'user_id': '*****@*****.**',
                           'factors': [{'type': 'password',
                                        'H1': H1,
                                        'credential_id': cred_id,
                                        },
                                       ],
                           },
             }
        j = json.dumps(a)

        # make sure credential does not exist in credstore
        self.assertIsNone(self.credstore.get_credential(cred_id))

        response = self.request('/add_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        res = json.loads(response.body[0])
        expected = {'add_creds_response': {'version': 1,
                                           'success': True,
                                           }
                    }
        self.assertEqual(res, expected)

        cred = self.credstore.get_credential(cred_id)
        print "ADDED CRED {!r}".format(cred)
        self.assertEqual(cred.status(), 'active')

        # Now, revoke the credential we added
        a = {'revoke_creds': {'version': 1,
                              'user_id': '*****@*****.**',
                              'factors': [{'reason': 'Just testing',
                                           'reference': '',
                                           'credential_id': cred_id,
                                           },
                                          ],
                              }
             }
        j = json.dumps(a)
        response = self.request('/revoke_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        res = json.loads(response.body[0])
        expected = {'revoke_creds_response': {'version': 1,
                                              'success': True,
                                              },
                    }
        self.assertEqual(res, expected)

        revoked = self.credstore.get_credential(cred_id, check_revoked = False)
        print "REVOKED CRED {!r}".format(revoked)
        self.assertEqual(revoked.status(), 'revoked')
        got_info = revoked.revocation_info()
        print "REVOCATION INFO: {!r}".format(got_info)
        expected_info = {'timestamp': got_info.get('timestamp'), # copy since it is a timestamp
                         'client_ip': '127.0.0.127',
                         'reason': 'Just testing',
                         'reference': '',
        }
        self.assertEqual(revoked.revocation_info(), expected_info)
        # check the timestamp
        now = int(time.time())
        self.assertGreater(got_info.get('timestamp'), now - 10)
        self.assertLess(got_info.get('timestamp'), now + 1)

        with self.assertRaises(vccs_auth.credential.VCCSAuthCredentialError):
            # make sure an exception is raised for revoked credential without check_revoked=False
            self.credstore.get_credential(cred_id)

    def test_revoke_creds_request2(self):
        """
        Verify revoke_creds for unknown credential
        """
        H1 = self._bcrypt_hash('foobar')
        cred_id = u'0'
        a = {'revoke_creds': {'version': 1,
                              'user_id': '*****@*****.**',
                              'factors': [{'reason': 'Just testing',
                                           'reference': '',
                                           'credential_id': cred_id,
                                           },
                                          ],
                              },
             }
        j = json.dumps(a)

        response = self.request('/revoke_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE1 {!r}: {!r}".format(response.status, response.body)
        self.assertIn('Unknown credential: {!r}'.format(cred_id), response.body[0])
        self.assertEqual(response.output_status, '500 Internal Server Error')

        # try again with blinding
        self.authbackend.expose_real_errors = False
        response = self.request('/revoke_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                request = j)
        print "RESPONSE2 {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '500 Internal Server Error')
        self.assertEqual(response.body, [])

    def test_revoke_missing_data(self):
        """
        Verify revoke request with missing data is rejected
        """
        for req_field in ['credential_id', 'reason', 'reference']:
            a = {'revoke_creds': {'version': 1,
                                  'user_id': '*****@*****.**',
                                  'factors': [{'reason': 'Just testing',
                                               'reference': '',
                                               'credential_id': 4750,
                                               },
                                              ],
                                  },
                 }
            del a['revoke_creds']['factors'][0][req_field]
            j = json.dumps(a)
            response = self.request('/revoke_creds', return_error = True, remote_hp = '127.0.0.127:50001',
                                    request = j)
            self.assertIn("No '{!s}' in credential to revoke".format(req_field), response.body[0])

    def test_revoke_creds_request3(self):
        """
        Verify revoke_creds from wrong source IP
        """
        a = {'revoke_creds': {'version': 1,
                              'user_id': '*****@*****.**',
                              'factors': [],
                              },
             }
        j = json.dumps(a)

        response = self.request('/revoke_creds', return_error = True, remote_hp = '127.128.129.130:50001',
                                request = j)
        print "RESPONSE {!r}: {!r}".format(response.status, response.body)
        self.assertEqual(response.output_status, '403 Forbidden')
예제 #6
0
파일: test_oath.py 프로젝트: SUNET/VCCS
class TestOathAuthentication(unittest.TestCase):

    def setUp(self):
        debug = False
        datadir = pkg_resources.resource_filename(__name__, 'data')
        self.config_file = os.path.join(datadir, 'test_config.ini')
        self.config = vccs_auth.config.VCCSAuthConfig(self.config_file, debug)
        self.key_handle = 0x2001
        self.keys = {self.key_handle: str('2001' * 16).decode('hex'),
                     }
        self.hasher = vccs_auth.hasher.VCCSSoftHasher(self.keys, vccs_auth.hasher.NoOpLock())
        self.logger = FakeLogger()
        self.credstore = FakeCredentialStore(creds={})

        self.test_key = '3132333435363738393031323334353637383930'.decode('hex')
        self.nonce = '010203040506'.decode('hex')
        flags = struct.pack('< I', pyhsm.defines.YSM_HMAC_SHA1_GENERATE)
        self.aead = pyhsm.soft_hsm.aesCCM(self.keys[self.key_handle], self.key_handle, self.nonce,
                                          self.test_key + flags, decrypt = False)
        print "Generated AEAD {!r}".format(self.aead.encode('hex'))


    def test_OATH_HOTP_1(self):
        """
        Test OATH HOTP (event based) authentication.
        """
        user_id = '*****@*****.**'
        # Generate an AEAD with the OATH RFC test key
        cred_dict = {'status' : 'active',
                     'nonce' : self.nonce,
                     'version' : 'NDNv1',
                     'credential_id' : '4712',
                     'key_handle' : self.key_handle,
                     'aead' : self.aead,
                     'type' : 'oath-hotp',
                     'digits' : 6,
                     'oath_counter' : 1,
                     'user_id': user_id,
                     }
        cred = vccs_auth.credential.from_dict(cred_dict, {})
        self.credstore.add_credential(cred)

        # this request matches the examples/example-oath-json output
        req = {
            'credential_id': cred.id(),
            'type': 'oath-hotp',
            'user_code': '338314',
            }

        factor = vccs_auth.oath.from_factor(req, 'auth', user_id, self.credstore, self.config)
        self.assertTrue(factor.authenticate(self.hasher, None, self.logger))

        # test with the same code again (should fail, not because of re-use but because
        # the starting offset of the credential has now moved past where the user_code
        # was found)
        self.assertFalse(factor.authenticate(self.hasher, None, self.logger))

        # test with next code (OATH RFC test vector, counter = 5)
        req['user_code'] = '254676'
        factor = vccs_auth.oath.from_factor(req, 'auth', user_id, self.credstore, self.config)
        self.assertTrue(factor.authenticate(self.hasher, None, self.logger))

    def test_OATH_HOTP_bad_user_id(self):
        """
        Test OATH HOTP (event based) authentication with someone else's credential.
        """
        user_id = '*****@*****.**'
        # Generate an AEAD with the OATH RFC test key
        cred_dict = {'status' : 'active',
                     'nonce' : self.nonce,
                     'version' : 'NDNv1',
                     'credential_id' : '4712',
                     'key_handle' : self.key_handle,
                     'aead' : self.aead,
                     'type' : 'oath-hotp',
                     'digits' : 6,
                     'oath_counter' : 1,
                     'user_id': user_id,
                     }
        cred = vccs_auth.credential.from_dict(cred_dict, {})
        self.credstore.add_credential(cred)

        # this request matches the examples/example-oath-json output
        req = {
            'credential_id': cred.id(),
            'type': 'oath-hotp',
            'user_code': '338314',
            }

        factor = vccs_auth.oath.from_factor(req, 'auth', '*****@*****.**', self.credstore, self.config)
        self.assertFalse(factor.authenticate(self.hasher, None, self.logger))


    def test_OATH_TOTP_1(self):
        """
        Test OATH TOTP (time based) authentication.
        """
        user_id = '*****@*****.**'
        # Generate an AEAD with the OATH RFC test key
        cred_dict = {'status': 'active',
                     'nonce': self.nonce,
                     'version': 'NDNv1',
                     'credential_id': '4712',
                     'key_handle': self.key_handle,
                     'aead': self.aead,
                     'type': 'oath-totp',
                     'digits': 8,
                     'oath_counter': (int(time.time()) / 30) - 10,
                     'user_id': user_id,
                     }
        cred = vccs_auth.credential.from_dict(cred_dict, {})
        self.credstore.add_credential(cred)

        correct_code = _get_oath_code(self.test_key, (int(time.time()) / 30), cred.digits())

        req = {
            'credential_id': cred.id(),
            'type': 'oath-totp',
            'user_code': str((correct_code - 11111111) % 10000000),
            }

        factor = vccs_auth.oath.from_factor(req, 'auth', user_id, self.credstore, self.config)
        # Try with incorrect OATH code
        self.assertFalse(factor.authenticate(self.hasher, None, self.logger))

        # Try with correct code
        req['user_code'] = str(correct_code)
        factor = vccs_auth.oath.from_factor(req, 'auth', user_id, self.credstore, self.config)
        self.assertTrue(factor.authenticate(self.hasher, None, self.logger))

        # Try with correct code again, should be refused (replay)
        factor = vccs_auth.oath.from_factor(req, 'auth', user_id, self.credstore, self.config)
        self.assertFalse(factor.authenticate(self.hasher, None, self.logger))

    def test_OATH_TOTP_bad_user_id(self):
        """
        Test OATH TOTP (time based) authentication with someone else's credential.
        """
        user_id = '*****@*****.**'
        # Generate an AEAD with the OATH RFC test key
        cred_dict = {'status': 'active',
                     'nonce': self.nonce,
                     'version': 'NDNv1',
                     'credential_id': '4712',
                     'key_handle': self.key_handle,
                     'aead': self.aead,
                     'type': 'oath-totp',
                     'digits': 8,
                     'oath_counter': (int(time.time()) / 30) - 10,
                     'user_id': user_id,
                     }
        cred = vccs_auth.credential.from_dict(cred_dict, {})
        self.credstore.add_credential(cred)

        correct_code = _get_oath_code(self.test_key, (int(time.time()) / 30), cred.digits())

        req = {
            'credential_id': cred.id(),
            'type': 'oath-totp',
            'user_code': str((correct_code - 11111111) % 10000000),
            }

        factor = vccs_auth.oath.from_factor(req, 'auth', '*****@*****.**', self.credstore, self.config)
        # Try with incorrect OATH code
        self.assertFalse(factor.authenticate(self.hasher, None, self.logger))