コード例 #1
0
def test_login():
    '''Performs a basic login intended to be successful'''

    dbconn = setup_test()
    dbdata = init_server(dbconn)
    conn = ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    # Most of the code which was originally written for this test is needed for other tests
    # because commands like PREREG require being logged in as the administrator. Both of these
    # functions still perform all the necessary tests that were originally done here.
    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    conn.send_message({'Action': "QUIT"})
コード例 #2
0
def test_setpassword():
    '''Tests the SETPASSWORD command'''
    dbconn = setup_test()
    dbdata = init_server(dbconn)
    conn = ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    badpwhash = '$argon2id$v=19$m=65536,t=2,' \
     'p=1$l0nvPkQDxJDKIMZsA96x4A$c5+XHmZjzSJIg3/vXXr33YNB1Jl52mdXtbMASLP1abs'
    newpwhash = '$argon2id$v=19$m=65536,t=2,' \
     'p=1$4WOWeLn7oOmrkp41zMzMcQ$8G51UCiIC/eETPJf0RZ5cNkX7jr3NkT92etTwNEO+f0'

    # Subtest #1: Failure because of wrong password sent
    conn.send_message({
        'Action': "SETPASSWORD",
        'Data': {
            'Password-Hash': badpwhash,
            'NewPassword-Hash': newpwhash
        }
    })

    response = conn.read_response(None)
    assert response['Code'] == 402 and response['Status'] == 'AUTHENTICATION FAILURE', \
     'test_setpassword(): Failed to catch bad password'

    # Subtest #2: Successful password change
    conn.send_message({
        'Action': "SETPASSWORD",
        'Data': {
            'Password-Hash': pwhash,
            'NewPassword-Hash': newpwhash
        }
    })

    response = conn.read_response(None)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_setpassword(): Failed to update admin password'

    conn.send_message({'Action': "QUIT"})
コード例 #3
0
def test_overflow():
    '''Tests the server's command handling for commands greater than 8K'''

    dbconn = setup_test()
    dbdata = init_server(dbconn)
    conn = serverconn.ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    conn.send_message({
        'Action': "REGISTER",
        'Data': {
            'Workspace-ID': 'A' * 10240,
            'Password-Hash': pwhash,
            'Device-ID': '11111111-1111-1111-1111-111111111111',
            'Device-Key': 'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 400 and response['Status'] == 'BAD REQUEST', \
     'test_overflow: failed to catch overflow'

    conn.send_message({'Action': "QUIT"})
コード例 #4
0
ファイル: test_keycmds.py プロジェクト: anselus/anselusd
def test_addentry_usercard():
    '''Tests the ADDENTRY and USERCARD command processes'''
    dbconn = setup_test()
    dbdata = init_server(dbconn)

    conn = ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    # Test setup is complete. Create a test keycard and do ADDENTRY

    # 1) Client sends the `ADDENTRY` command, attaching the entry data between the
    #    `----- BEGIN USER KEYCARD -----` header and the `----- END USER KEYCARD -----` footer.
    # 2) The server then checks compliance of the entry data. Assuming that it complies, the server
    #    generates a cryptographic signature and responds with `100 CONTINUE`, returning the
    #    signature, the hash of the data, and the hash of the previous entry in the database.
    # 3) The client verifies the signature against the organization’s verification key. This has
    #    the added benefit of ensuring that none of the fields were altered by the server and that
    #    the signature is valid.
    # 4) The client appends the hash from the previous entry as the `Previous-Hash` field
    # 5) The client verifies the hash value for the entry from the server and sets the `Hash` field
    # 6) The client signs the entry as the `User-Signature` field and then uploads the result to
    #    the server.
    # 7) Once uploaded, the server validates the `Hash` and `User-Signature` fields, and,
    #    assuming that all is well, adds it to the keycard database and returns `200 OK`.
    #
    # Once that monster of a process completes, the card should be successfully added, but we're not
    # done yet. From there, create a new user entry, chain it to the first, and upload it. This will
    # test the chaining code in the AddEntry command processing.
    #
    # Finally, once that entire mess is complete, send a USERCARD command and verify what is
    # returned against the data set up so far. It doesn't seem like piggybacking a test for a
    # different command off another is the right thing to do, but in this case, it's the perfect
    # setup to confirm that a user's entire keycard is handled properly.

    usercard = keycard.UserEntry()
    usercard.set_fields({
        'Name':
        'Test Administrator',
        'Workspace-ID':
        dbdata['admin_wid'],
        'User-ID':
        'admin',
        'Domain':
        'example.com',
        'Contact-Request-Verification-Key':
        'ED25519:d0-oQb;{QxwnO{=!|^62+E=UYk2Y3mr2?XKScF4D',
        'Contact-Request-Encryption-Key':
        'CURVE25519:yBZ0{1fE9{2<b~#i^R+JT-yh-y5M(Wyw_)}_SZOn',
        'Public-Encryption-Key':
        'CURVE25519:_`UC|vltn_%P5}~vwV^)oY){#uvQSSy(dOD_l(yE'
    })

    conn.send_message({
        'Action': "ADDENTRY",
        'Data': {
            'Base-Entry': usercard.make_bytestring(0).decode()
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 100 and \
     response['Status'] == 'CONTINUE' and \
     'Organization-Signature' in response['Data'] and \
     'Hash' in response['Data'] and \
     'Previous-Hash' in response['Data'], 'test_addentry(): server did return all needed fields'

    usercard.signatures['Organization'] = response['Data'][
        'Organization-Signature']

    # A regular client will check the entry cache, pull updates to the org card, and get the
    # verification key. Because this is just an integration test, we skip all that and just use
    # the known verification key from earlier in the test.
    status = usercard.verify_signature(CryptoString(dbdata['ovkey']),
                                       'Organization')
    assert not status.error(
    ), f"test_addentry(): org signature didn't verify: {status.info()}"

    assert response['Data']['Previous-Hash'] == dbdata['second_org_entry'].hash, \
     "test_addentry(): server did not attach correct Previous Hash to root user entry"

    usercard.prev_hash = response['Data']['Previous-Hash']
    usercard.hash = response['Data']['Hash']
    status = usercard.verify_hash()
    assert not status.error(
    ), f"test_addentry(): hash didn't verify: {status.info()}"

    # User sign and verify
    skey = CryptoString('ED25519:ip52{ps^jH)t$k-9bc_RzkegpIW?}FFe~BX&<V}9')
    assert skey.is_valid(
    ), "test_addentry(): failed to set user's cr signing key"
    status = usercard.sign(skey, 'User')
    assert not status.error(), "test_addentry(): failed to user sign"

    vkey = CryptoString('ED25519:d0-oQb;{QxwnO{=!|^62+E=UYk2Y3mr2?XKScF4D')
    assert vkey.is_valid(
    ), "test_addentry(): failed to set user's cr verification key"
    status = usercard.verify_signature(vkey, 'User')

    status = usercard.is_compliant()
    assert not status.error(
    ), f"test_addentry(): compliance error: {str(status)}"

    conn.send_message({
        'Action': "ADDENTRY",
        'Data': {
            'User-Signature': usercard.signatures['User']
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and \
     response['Status'] == 'OK', f"test_addentry(): final upload server error {response}"

    # Now to test ADDENTRY with a chained entry. Hold on tight!

    # Submit the chained entry
    newkeys = usercard.chain(skey, True)
    assert not newkeys.error(
    ), f"test_addentry(): new entry failed to chain: {newkeys.info()}"

    second_user_entry = newkeys['entry']
    conn.send_message({
        'Action': "ADDENTRY",
        'Data': {
            'Base-Entry': second_user_entry.make_bytestring(1).decode()
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 100 and \
     response['Status'] == 'CONTINUE' and \
     'Organization-Signature' in response['Data'] and \
     'Hash' in response['Data'] and \
     'Previous-Hash' in response['Data'], 'test_addentry(): server did return all needed fields'

    second_user_entry.signatures['Organization'] = response['Data'][
        'Organization-Signature']

    # Verify the server's signature, add and verify the hashes, sign, and upload
    status = second_user_entry.verify_signature(CryptoString(dbdata['ovkey']),
                                                'Organization')
    assert not status.error(
    ), f"test_addentry(): org signature didn't verify: {status.info()}"

    second_user_entry.prev_hash = response['Data']['Previous-Hash']
    assert response['Data']['Previous-Hash'] == usercard.hash, \
     "Server did not return correct chained user entry hash"
    second_user_entry.hash = response['Data']['Hash']
    status = second_user_entry.verify_hash()
    assert not status.error(
    ), f"test_addentry(): hash didn't verify: {status.info()}"

    skey = CryptoString(newkeys['crsign.private'])
    assert skey.is_valid(), "test_addentry(): failed to set user signing key"
    status = second_user_entry.sign(skey, 'User')
    assert not status.error(), "test_addentry(): failed to user sign"

    vkey = CryptoString(newkeys['crsign.public'])
    assert vkey.is_valid(
    ), "test_addentry(): failed to set user verification key"
    status = second_user_entry.verify_signature(vkey, 'User')

    status = second_user_entry.is_compliant()
    assert not status.error(
    ), f"test_addentry(): compliance error: {str(status)}"

    conn.send_message({
        'Action': "ADDENTRY",
        'Data': {
            'User-Signature': second_user_entry.signatures['User']
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and \
     response['Status'] == 'OK', f"test_addentry(): final upload server error {response}"

    conn.send_message({
        'Action': "USERCARD",
        'Data': {
            'Owner': 'admin/example.com',
            'Start-Index': '1'
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 104 and response['Status'] == 'TRANSFER', \
     'test_addentry.usercard: server returned %s' % response['Status']
    assert response['Data']['Item-Count'] == '2', \
     'test_addentry.usercard: server returned wrong number of items'
    data_size = int(response['Data']['Total-Size'])
    conn.send_message({'Action': 'TRANSFER'})

    chunks = list()
    tempstr = conn.read()
    data_read = len(tempstr)
    chunks.append(tempstr)
    while data_read < data_size:
        tempstr = conn.read()
        data_read = data_read + len(tempstr)
        chunks.append(tempstr)

    assert data_read == data_size, 'test_orgcard.usercard: size mismatch'

    # Now that the data has been downloaded, we put it together and split it properly. We should
    # have two entries
    entries = ''.join(chunks).split('----- END USER ENTRY -----\r\n')
    if entries[-1] == '':
        entries.pop()

    # These entries are added to the database in init_server(). The insert operations are not
    # done here because the two org entries are needed for other tests, as well.
    assert len(
        entries
    ) == 2, "test_orgcard.usercard: server did not send the expected entry"
    assert entries[1] == '----- BEGIN USER ENTRY -----\r\n' + \
     second_user_entry.make_bytestring(-1).decode(), \
     "test_orgcard.usercard: entry didn't match"

    conn.send_message({'Action': "QUIT"})
コード例 #5
0
def test_set_status():
    '''Tests the SETSTATUS command'''

    dbconn = setup_test()
    dbdata = init_server(dbconn)

    uid = 'csimons'
    domain = 'example.net'

    conn = ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    # Prereg with a test user
    conn.send_message({
        'Action': "PREREG",
        'Data': {
            'User-ID': uid,
            'Domain': domain
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_set_status: failed to prereg test user'

    # Call REGCODE to actually register the user
    regdata = response
    pwd = Password()
    status = pwd.Set('ShrivelCommuteGottenAgonizingElbowQuiver')
    assert not status.error(), 'test_set_status: Failed to set password'
    devid = '0e6406e3-1831-4352-9fbe-0de8faebf0f0'
    devkey = EncryptionPair()

    # Subtest #2: Regcode with User ID and domain
    conn.send_message({
        'Action': "REGCODE",
        'Data': {
            'User-ID': regdata['Data']['User-ID'],
            'Domain': regdata['Data']['Domain'],
            'Reg-Code': regdata['Data']['Reg-Code'],
            'Password-Hash': pwd.hashstring,
            'Device-ID': devid,
            'Device-Key': devkey.get_public_key()
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 201 and response['Status'] == 'REGISTERED', \
     'test_set_status: failed to register test user'

    conn.send_message({
        'Action': 'SETSTATUS',
        'Data': {
            'Workspace-ID': regdata['Data']['Workspace-ID'],
            'Status': 'disabled'
        }
    })
    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_set_status: failed to disable test user'
コード例 #6
0
def test_devkey():
    '''Tests the DEVKEY command'''
    dbconn = setup_test()
    dbdata = init_server(dbconn)
    conn = ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    # Most of the code which was originally written for this test is needed for other tests
    # because commands like PREREG require being logged in as the administrator. Both of these
    # functions still perform all the necessary tests that were originally done here.
    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    newdevpair = EncryptionPair(
        CryptoString(r'CURVE25519:F0HjK;dB8tr<*2UkaHP?e1-tWAohWJ?IP+oP@o@C'),
        CryptoString(r'CURVE25519:|Cs(42=7FEwCoKG|5fVPC%MR6gD)_{h}}?ah%cIn'))

    conn.send_message({
        'Action': 'DEVKEY',
        'Data': {
            'Device-ID': devid,
            'Old-Key': dbdata['devpair'].get_public_key(),
            'New-Key': newdevpair.get_public_key()
        }
    })

    response = conn.read_response(None)
    assert response != 100 and response['Status'] == 'CONTINUE' and \
     'Challenge' in response['Data'] and 'New-Challenge' in response['Data'], \
     "test_devkey(): server failed to return new and old key challenge"

    msg = {'Action': "DEVKEY", 'Data': {}}

    status = devpair.decrypt(response['Data']['Challenge'])
    assert not status.error(
    ), 'login_devkey(): failed to decrypt device challenge for old key'
    msg['Data']['Response'] = status['data']

    status = newdevpair.decrypt(response['Data']['New-Challenge'])
    assert not status.error(
    ), 'login_devkey(): failed to decrypt device challenge for new key'
    msg['Data']['New-Response'] = status['data']

    conn.send_message(msg)

    response = conn.read_response(None)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'Server challenge-response phase failed'

    conn.send_message({'Action': "QUIT"})
コード例 #7
0
def test_resetpassword():
    '''Tests the RESETPASSWORD command'''
    dbconn = setup_test()
    dbdata = init_server(dbconn)

    conn = ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    init_user(dbdata, conn)

    # Subtest #1: Reset user password, server generates passcode and expiration
    conn.send_message({
        'Action': "RESETPASSWORD",
        'Data': {
            'Workspace-ID': dbdata['user_wid']
        }
    })

    response = conn.read_response(None)
    assert response['Code'] == 200 and response['Status'] == "OK", \
     "test_resetpassword(): subtest #1: server returned an error"
    assert 'Expires' in response['Data'] and 'Reset-Code' in response['Data'], \
     "test_resetpassword(): subtest #1: server didn't return all required fields"

    # Subtest #2: Reset user password, admin generates passcode and expiration
    expiration = datetime.datetime.utcnow() + datetime.timedelta(minutes=45)

    conn.send_message({
        'Action': "RESETPASSWORD",
        'Data': {
            'Workspace-ID': dbdata['user_wid'],
            'Reset-Code': 'barbarian-chivalry-dungeon',
            'Expires': expiration.strftime(r'%Y%m%dT%H%M%SZ')
        }
    })

    response = conn.read_response(None)
    assert response['Code'] == 200 and response['Status'] == "OK", \
     "test_resetpassword(): subtest #2: server returned an error"
    assert 'Expires' in response['Data'] and 'Reset-Code' in response['Data'], \
     "test_resetpassword(): subtest #2: server didn't return all required fields"

    conn.send_message({'Action': 'LOGOUT', 'Data': {}})
    response = conn.read_response(None)
    assert response[
        'Code'] == 200, 'test_resetpassword(): failed to log admin out'

    # Subtest #3: Failed attempt to complete the password reset
    newpassword = Password('SomeOth3rPassw*rd')
    conn.send_message({
        'Action': "PASSCODE",
        'Data': {
            'Workspace-ID': dbdata['user_wid'],
            'Reset-Code': 'wrong-reset-code',
            'Password-Hash': newpassword.hashstring
        }
    })
    response = conn.read_response(None)
    assert response['Code'] == 402 and response['Status'] == "AUTHENTICATION FAILURE", \
     "test_resetpassword(): subtest #3: server failed to catch a bad password"

    # Subtest #4: Successfully complete the password reset
    conn.send_message({
        'Action': "PASSCODE",
        'Data': {
            'Workspace-ID': dbdata['user_wid'],
            'Reset-Code': 'barbarian-chivalry-dungeon',
            'Password-Hash': newpassword.hashstring
        }
    })
    response = conn.read_response(None)
    assert response['Code'] == 200 and response['Status'] == "OK", \
     "test_resetpassword(): subtest #4: server returned an error"
コード例 #8
0
def test_prereg():
    '''Tests the server's PREREG command with failure conditions'''

    dbconn = setup_test()
    dbdata = init_server(dbconn)

    uid = 'TestUserID'
    wid = '11111111-1111-1111-1111-111111111111'
    domain = 'acme.com'

    conn = ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    # Subtest #1: Prereg with user ID and domain
    conn.send_message({
        'Action': "PREREG",
        'Data': {
            'User-ID': uid,
            'Domain': domain
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_prereg: subtest #1 returned an error'
    assert response['Data']['User-ID'] == uid, \
     'test_prereg: wrong user ID in subtest #1'
    assert response['Data']['Domain'] == domain, \
     'test_prereg: wrong domain in subtest #1'
    assert validate_uuid(
        response['Data']['Workspace-ID']), 'Server returned a bad WID'
    assert len(response['Data']['Workspace-ID']) <= 128, \
     'Server returned a regcode longer than allowed'

    # REGCODE subtest setup
    regdata = response
    pwd = Password()
    status = pwd.Set('ShrivelCommuteGottenAgonizingElbowQuiver')
    assert not status.error(), 'test_prereg: Failed to set password'
    devid = '0e6406e3-1831-4352-9fbe-0de8faebf0f0'
    devkey = EncryptionPair()

    # Subtest #2: Regcode with User ID and domain
    conn.send_message({
        'Action': "REGCODE",
        'Data': {
            'User-ID': regdata['Data']['User-ID'],
            'Domain': regdata['Data']['Domain'],
            'Reg-Code': regdata['Data']['Reg-Code'],
            'Password-Hash': pwd.hashstring,
            'Device-ID': devid,
            'Device-Key': devkey.get_public_key()
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 201 and response['Status'] == 'REGISTERED', \
     'test_prereg: subtest #2 returned an error'

    # Subtest #3: Plain prereg
    conn.send_message({'Action': "PREREG", 'Data': {}})

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_prereg: subtest #2 returned an error'
    assert validate_uuid(
        response['Data']['Workspace-ID']), 'Server returned a bad WID'
    assert len(response['Data']['Workspace-ID']) <= 128, \
     'Server returned a regcode longer than allowed'

    # Subtest #4: Plain regcode
    regdata = response
    conn.send_message({
        'Action': "REGCODE",
        'Data': {
            'Workspace-ID': regdata['Data']['Workspace-ID'],
            'Reg-Code': regdata['Data']['Reg-Code'],
            'Password-Hash': pwd.hashstring,
            'Device-ID': devid,
            'Device-Key': devkey.get_public_key()
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 201 and response['Status'] == 'REGISTERED', \
     'test_prereg: subtest #4 returned an error'

    # Subtest #5: duplicate user ID
    conn.send_message({
        'Action': "PREREG",
        'Data': {
            'User-ID': uid,
            'Domain': domain
        }
    })
    response = conn.read_response(server_response)
    assert response['Code'] == 408 and response['Status'] == 'RESOURCE EXISTS', \
     'test_prereg: subtest #3 failed to catch duplicate user'

    # Subtest #6: WID as user ID
    conn.send_message({'Action': "PREREG", 'Data': {'User-ID': wid}})

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_prereg: subtest #4 returned an error'
    assert response['Data']['Workspace-ID'] == wid, 'Server returned a bad WID'
    assert len(response['Data']['Workspace-ID']) <= 128, \
     'Server returned a regcode longer than allowed'

    # Subtest #7: Specify WID
    wid = '22222222-2222-2222-2222-222222222222'
    conn.send_message({'Action': "PREREG", 'Data': {'Workspace-ID': wid}})

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_prereg: subtest #4 returned an error'
    assert response['Data']['Workspace-ID'] == wid, 'Server returned a bad WID'
    assert len(response['Data']['Workspace-ID']) <= 128, \
     'Server returned a regcode longer than allowed'

    # Subtest #8: Specify User ID only.
    uid = 'TestUserID2'
    conn.send_message({'Action': "PREREG", 'Data': {'User-ID': uid}})

    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK', \
     'test_prereg: subtest #6 returned an error'
    assert response['Data'][
        'User-ID'] == uid, 'Server returned the wrong user ID'
    assert validate_uuid(
        response['Data']['Workspace-ID']), 'Server returned a bad WID'
    assert len(response['Data']['Workspace-ID']) <= 128, \
     'Server returned a regcode longer than allowed'

    conn.send_message({'Action': "QUIT"})
コード例 #9
0
def test_register_failures():
    '''Tests the server's REGISTER command with failure conditions'''

    # Testing the REGISTER command only works when the server uses either network or public mode
    serverconfig = load_server_config_file()
    if serverconfig['global']['registration'] not in ['network', 'public']:
        return

    dbconn = setup_test()
    dbdata = init_server(dbconn)
    conn = serverconn.ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    # Test #1: Attempt registration with unsupported encryption type

    conn.send_message({
        'Action': "REGISTER",
        'Data': {
            'Workspace-ID': '11111111-1111-1111-1111-222222222222',
            'Password-Hash': pwhash,
            'Device-ID': '11111111-1111-1111-1111-111111111111',
            'Device-Key': '3DES:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 309 and response['Status'] == 'ENCRYPTION TYPE NOT SUPPORTED', \
     'test_register_failures: subtest #1 failed to catch unsupported encryption'

    # Test #2: Send bad WID

    conn.send_message({
        'Action': "REGISTER",
        'Data': {
            'Workspace-ID':
            'AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA',
            'Password-Hash': pwhash,
            'Device-ID': '11111111-1111-1111-1111-111111111111',
            'Device-Key': 'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 400 and response['Status'] == 'BAD REQUEST', \
     'test_register_failures: subtest #2 failed to catch a bad WID'

    conn.send_message({'Action': "QUIT"})
コード例 #10
0
def test_register():
    '''Tests the server's REGISTER command - success and duplicate WID condition'''

    # Testing the REGISTER command only works when the server uses either network or public mode
    serverconfig = load_server_config_file()
    if serverconfig['global']['registration'] not in ['network', 'public']:
        return

    dbconn = setup_test()
    dbdata = init_server(dbconn)
    conn = serverconn.ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    wid = '11111111-1111-1111-1111-111111111111'
    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devkey = 'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'

    # Subtest #1: Regular registration that is supposed to succeed
    conn.send_message({
        'Action': "REGISTER",
        'Data': {
            'Workspace-ID': wid,
            'Password-Hash': pwhash,
            'Device-ID': '11111111-1111-1111-1111-111111111111',
            'Device-Key': devkey
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 201 and response['Status'] == 'REGISTERED', \
     'test_register: subtest #1 returned an error'

    # Subtest #2: Attempt registration of existing WID

    conn.send_message({
        'Action': "REGISTER",
        'Data': {
            'Workspace-ID': wid,
            'Password-Hash': pwhash,
            'Device-ID': '11111111-1111-1111-1111-111111111111',
            'Device-Key': devkey
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 408 and response['Status'] == 'RESOURCE EXISTS', \
     'test_register: subtest #2 failed to catch duplicate registration'

    conn.send_message({'Action': "QUIT"})
コード例 #11
0
def test_unregister():
    '''Test the UNREGISTER command'''

    # Testing the UNREGISTER command only works when the server uses either network or public mode
    serverconfig = load_server_config_file()
    if serverconfig['global']['registration'] not in ['network', 'public']:
        return

    dbconn = setup_test()
    dbdata = init_server(dbconn)
    conn = serverconn.ServerConnection()
    assert conn.connect('localhost',
                        2001), "Connection to server at localhost:2001 failed"

    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devid = '22222222-2222-2222-2222-222222222222'
    devpair = EncryptionPair(
        CryptoString(r'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'),
        CryptoString(r'CURVE25519:W30{oJ?w~NBbj{F8Ag4~<bcWy6_uQ{i{X?NDq4^l'))

    dbdata['pwhash'] = pwhash
    dbdata['devid'] = devid
    dbdata['devpair'] = devpair

    regcode_admin(dbdata, conn)
    login_admin(dbdata, conn)

    userwid = '11111111-1111-1111-1111-111111111111'
    # password is 'SandstoneAgendaTricycle'
    pwhash = '$argon2id$v=19$m=65536,t=2,p=1$ew5lqHA5z38za+257DmnTA$0LWVrI2r7XCq' \
       'dcCYkJLok65qussSyhN5TTZP+OTgzEI'
    devkey = 'CURVE25519:@X~msiMmBq0nsNnn0%~x{M|NU_{?<Wj)cYybdh&Z'

    conn.send_message({
        'Action': "REGISTER",
        'Data': {
            'Workspace-ID': userwid,
            'Password-Hash': pwhash,
            'Device-ID': devid,
            'Device-Key': devkey
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 201 and response['Status'] == 'REGISTERED', \
     f"test_unregister: test user registration failed: {response['Status']}"

    # Subtest #1: Try to unregister the admin account
    conn.send_message({
        'Action': "UNREGISTER",
        'Data': {
            'Password-Hash': pwhash
        }
    })
    response = conn.read_response(server_response)
    assert response['Code'] == 403 and response['Status'] == 'FORBIDDEN', \
     "test_unregister(): failed to properly handle trying to unregister admin account"

    conn.send_message({'Action': "LOGOUT", 'Data': {}})
    response = conn.read_response(server_response)
    assert response['Code'] == 200 and response['Status'] == 'OK'

    # Set up for subtest #2: log in as the user
    status = serverconn.login(conn, userwid, CryptoString(dbdata['oekey']))
    assert not status.error(
    ), f"test_unregister(): user login phase failed: {status.info()}"

    status = serverconn.password(conn, userwid, pwhash)
    assert not status.error(
    ), f"test_unregister(): password phase failed: {status.info()}"

    status = serverconn.device(conn, devid, devpair)
    assert not status.error(
    ), f"test_unregister(): device phase failed: {status.info()}"

    # As a general rule, these anselusd integration tests don't call the regular pyanselus client
    # library calls because we do extra validation. However, we're going to make an exception in
    # this test because LOGIN and ADDENTRY are both really big.
    usercard = keycard.UserEntry()
    usercard.set_fields({
        'Name':
        'Corbin Simons',
        'Workspace-ID':
        userwid,
        'User-ID':
        'csimons',
        'Domain':
        'example.com',
        'Contact-Request-Verification-Key':
        'ED25519:E?_z~5@+tkQz!iXK?oV<Zx(ec;=27C8Pjm((kRc|',
        'Contact-Request-Encryption-Key':
        'CURVE25519:yBZ0{1fE9{2<b~#i^R+JT-yh-y5M(Wyw_)}_SZOn',
        'Public-Encryption-Key':
        'CURVE25519:_`UC|vltn_%P5}~vwV^)oY){#uvQSSy(dOD_l(yE'
    })

    crspair = SigningPair(
        CryptoString(r'ED25519:E?_z~5@+tkQz!iXK?oV<Zx(ec;=27C8Pjm((kRc|'),
        CryptoString(r'ED25519:u4#h6LEwM6Aa+f<++?lma4Iy63^}V$JOP~ejYkB;'))

    status = usercard.is_data_compliant()
    assert not status.error(
    ), f"test_unregister: user card not compliant: {status.info()}"
    status = serverconn.addentry(conn, usercard, CryptoString(dbdata['ovkey']),
                                 crspair)
    assert not status.error(), f"test_unregister: addentry() failed: {status.info()}\n" \
     f"Server Info: {status['Info']}"

    # Subtest #2: Unregister regular user from admin account
    conn.send_message({
        'Action': "UNREGISTER",
        'Data': {
            'Workspace-ID': userwid,
            'Password-Hash': pwhash
        }
    })

    response = conn.read_response(server_response)
    assert response['Code'] == 202 and response['Status'] == 'UNREGISTERED', \
     f"test_unregister(): user unregistration failed: {response['Status']}"

    # Check to make sure the database end was handled correctly
    cur = dbconn.cursor()
    cur.execute('SELECT password,status FROM workspaces WHERE wid = %s ',
                (userwid, ))
    row = cur.fetchone()
    assert row, "test_unregister(): cleanup check query found no rows"
    assert row[0] == '-' and row[1] == 'deleted', \
     "test_unregister(): server failed to clean up database properly"

    conn.send_message({'Action': "QUIT"})