hssh-0.1.0.0: test/Spec/Server/Service/UserAuth.hs
{-# LANGUAGE OverloadedStrings #-}
module Spec.Server.Service.UserAuth ( tests ) where
import Control.Concurrent.Async
import Crypto.Error
import qualified Crypto.PubKey.Ed25519 as Ed25519
import qualified Crypto.PubKey.RSA as RSA
import qualified Data.ByteString as BS
import Data.Default
import Test.Tasty
import Test.Tasty.HUnit
import Network.SSH.Internal
import Spec.Util
tests :: TestTree
tests = testGroup "Network.SSH.Server.Service.UserAuth"
[ testGroup "service inactive (state 0)"
[ testInactive01
, testInactive02
, testInactive03
]
, testGroup "service active (state 1)"
[ testActive01
, testActive02
, testActive03
, testActive04
, testActive05
, testActive06
, testActive07
]
]
testInactive01 :: TestTree
testInactive01 = testCase "request user auth service" $ do
(client, server) <- newDummyTransportPair
withAsync (withAuthentication def server sess with) $ \_ -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
where
sess = SessionId mempty
with _ = Just undefined
req0 = ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
testInactive02 :: TestTree
testInactive02 = testCase "request other service" $ do
(client, server) <- newDummyTransportPair
withAsync (withAuthentication def server sess with) $ \thread -> do
sendMessage client req0
assertThrows "exp0" exp0 (wait thread)
where
sess = SessionId mempty
with _ = Just undefined
req0 = ServiceRequest (Name "other-service")
exp0 = exceptionServiceNotAvailable
testInactive03 :: TestTree
testInactive03 = testCase "dispatch other message" $ do
(client, server) <- newDummyTransportPair
withAsync (withAuthentication def server sess with) $ \thread -> do
sendMessage client req0
assertThrows "exp0" exp0 (wait thread)
where
sess = SessionId mempty
with _ = Just undefined
req0 = MsgUnknown 1
exp0 = exceptionUnexpectedMessage "\x01"
testActive01 :: TestTree
testActive01 = testCase "authenticate by public key (no signature)" $ do
let config = def { onAuthRequest = onAuth }
(client, server) <- newDummyTransportPair
withAsync (withAuthentication config server sess with) $ \_ -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
sendMessage client req1
receiveMessage client >>= assertEqual "res1" res1
where
with _ = Just undefined
user = Name "fnord"
srvc = Name "ssh-connection"
sess = SessionId "\196\249b\160;FF\DLE\173\&1>\179w=\238\210\140\&8!:\139=QUx\169C\209\165\FS\185I"
pubk = PublicKeyEd25519 (pass $ Ed25519.publicKey ("\185\EOT\150\CAN\142)\175\161\242\141/\SI\214=n$?\189Z\172\214\190\EM\190^\226\r\241\197\&8\235\130" :: BS.ByteString))
auth = AuthPublicKey pubk Nothing
req0 = MsgServiceRequest $ ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
req1 = MsgUserAuthRequest $ UserAuthRequest user srvc auth
res1 = UserAuthPublicKeyOk pubk
pass (CryptoPassed x) = x
pass _ = undefined
onAuth _ _ _ = pure (Just user)
testActive02 :: TestTree
testActive02 = testCase "authenticate by public key (incorrect signature)" $ do
let config = def { onAuthRequest = onAuth }
(client, server) <- newDummyTransportPair
withAsync (withAuthentication config server sess with) $ \_ -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
sendMessage client req1
receiveMessage client >>= assertEqual "res1" res1
where
with _ = Just undefined
user = Name "fnord"
srvc = Name "ssh-connection"
sess = SessionId "\196\249b\160;FF\DLE\173\&1>\179w=\238\210\140\&8!:\139=QUx\169C\209\165\FS\185I"
pubk = PublicKeyEd25519 (pass $ Ed25519.publicKey ("\185\EOT\150\CAN\142)\175\161\242\141/\SI\214=n$?\189Z\172\214\190\EM\190^\226\r\241\197\&8\235\130" :: BS.ByteString))
sign = SignatureEd25519 (pass $ Ed25519.signature ("\NUL\NULG\NULw2\NUL\b|\ETX\239\136\213&|\145Zp\ACK\240p\243\128\vL\139N\ESC\207LI\t?\139D\DC36\206\252p\172\190)\238 {\\*\206\203\253\176\vE\EM\SYNkG\211\&2\192\201\EOT\ACK" :: BS.ByteString))
auth = AuthPublicKey pubk (Just sign)
req0 = ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
req1 = UserAuthRequest user srvc auth
res1 = UserAuthFailure ["publickey"] False
pass (CryptoPassed x) = x
pass _ = undefined
onAuth _ _ _ = pure (Just user)
testActive03 :: TestTree
testActive03 = testCase "authenticate by public key (correct signature, user accepted)" $ do
let config = def { onAuthRequest = onAuth }
(client, server) <- newDummyTransportPair
withAsync (withAuthentication config server sess with) $ \thread -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
sendMessage client req1
receiveMessage client >>= assertEqual "res1" res1
wait thread >>= assertEqual "idnt" idnt
where
idnt = "identity" :: String
user = Name "fnord"
srvc = Name "ssh-connection"
sess = SessionId "\196\249b\160;FF\DLE\173\&1>\179w=\238\210\140\&8!:\139=QUx\169C\209\165\FS\185I"
pubk = PublicKeyEd25519 (pass $ Ed25519.publicKey ("\185\EOT\150\CAN\142)\175\161\242\141/\SI\214=n$?\189Z\172\214\190\EM\190^\226\r\241\197\&8\235\130" :: BS.ByteString))
sign = SignatureEd25519 (pass $ Ed25519.signature ("\152\211G\164w2\253\b|\ETX\239\136\213&|\145Zp\ACK\240p\243\128\vL\139N\ESC\207LI\t?\139D\DC36\206\252p\172\190)\238 {\\*\206\203\253\176\vE\EM\SYNkG\211\&2\192\201\EOT\ACK" :: BS.ByteString))
auth = AuthPublicKey pubk (Just sign)
req0 = ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
req1 = UserAuthRequest user srvc auth
res1 = UserAuthSuccess
pass (CryptoPassed x) = x
pass _ = undefined
with _ = Just pure
onAuth u s p
| u /= user = pure Nothing
| s /= srvc = pure Nothing
| p /= pubk = pure Nothing
| otherwise = pure (Just idnt)
testActive04 :: TestTree
testActive04 = testCase "authenticate by public key (correct signature, user accepted, service not available)" $ do
let config = def { onAuthRequest = \_ _ _ -> pure (Just idnt) }
(client, server) <- newDummyTransportPair
withAsync (withAuthentication config server sess with) $ \thread -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
sendMessage client req1
assertThrows "exp1" exp1 $ wait thread
where
idnt = "identity" :: String
user = Name "fnord"
srvc = Name "unavailable-service"
sess = SessionId "\196\249b\160;FF\DLE\173\&1>\179w=\238\210\140\&8!:\139=QUx\169C\209\165\FS\185I"
pubk = PublicKeyEd25519 (pass $ Ed25519.publicKey ("J\190r%\232\247\220\n\160\129m\132\RS\193\NULL\128\152}\142\SUB\161\f\229\f\137\254M\192>n\182" :: BS.ByteString))
sign = SignatureEd25519 (pass $ Ed25519.signature ("\244\173\199<\202 \204Q\185z\EOTU\v\236\&37\"u\248TE^3fk\158|@^\215\142\DC4\234\234\DC1\224\236\FS{\CAN\144^\140\148X\169\174+\\:y\226\&9K\141\182:\NUL_\245\DC1a\228\b" :: BS.ByteString))
auth = AuthPublicKey pubk (Just sign)
req0 = ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
req1 = UserAuthRequest user srvc auth
exp1 = Disconnect Local DisconnectServiceNotAvailable mempty
pass (CryptoPassed x) = x
pass _ = undefined
with s
| s == srvc = Nothing
| otherwise = Just pure
testActive05 :: TestTree
testActive05 = testCase "authenticate by public key (correct signature, user rejected)" $ do
let config = def { onAuthRequest = \_ _ _ -> pure Nothing }
(client, server) <- newDummyTransportPair
withAsync (withAuthentication config server sess with) $ \_ -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
sendMessage client req1
receiveMessage client >>= assertEqual "res1" res1
where
user = Name "fnord"
srvc = Name "ssh-connection"
sess = SessionId "\196\249b\160;FF\DLE\173\&1>\179w=\238\210\140\&8!:\139=QUx\169C\209\165\FS\185I"
pubk = PublicKeyEd25519 (pass $ Ed25519.publicKey ("\185\EOT\150\CAN\142)\175\161\242\141/\SI\214=n$?\189Z\172\214\190\EM\190^\226\r\241\197\&8\235\130" :: BS.ByteString))
sign = SignatureEd25519 (pass $ Ed25519.signature ("\152\211G\164w2\253\b|\ETX\239\136\213&|\145Zp\ACK\240p\243\128\vL\139N\ESC\207LI\t?\139D\DC36\206\252p\172\190)\238 {\\*\206\203\253\176\vE\EM\SYNkG\211\&2\192\201\EOT\ACK" :: BS.ByteString))
auth = AuthPublicKey pubk (Just sign)
req0 = ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
req1 = UserAuthRequest user srvc auth
res1 = UserAuthFailure ["publickey"] False
pass (CryptoPassed x) = x
pass _ = undefined
with _ = Just pure
testActive06 :: TestTree
testActive06 = testCase "authenticate by public key (key/signature type mismatch)" $ do
let config = def { onAuthRequest = \_ _ _ -> pure Nothing }
(client, server) <- newDummyTransportPair
withAsync (withAuthentication config server sess with) $ \_ -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
sendMessage client req1
receiveMessage client >>= assertEqual "res1" res1
where
user = Name "fnord"
srvc = Name "ssh-connection"
sess = SessionId "\196\249b\160;FF\DLE\173\&1>\179w=\238\210\140\&8!:\139=QUx\169C\209\165\FS\185I"
pubk = PublicKeyRSA $ RSA.PublicKey 24 65537 2834792
sign = SignatureEd25519 (pass $ Ed25519.signature ("\152\211G\164w2\253\b|\ETX\239\136\213&|\145Zp\ACK\240p\243\128\vL\139N\ESC\207LI\t?\139D\DC36\206\252p\172\190)\238 {\\*\206\203\253\176\vE\EM\SYNkG\211\&2\192\201\EOT\ACK" :: BS.ByteString))
auth = AuthPublicKey pubk (Just sign)
req0 = MsgServiceRequest $ ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
req1 = MsgUserAuthRequest $ UserAuthRequest user srvc auth
res1 = UserAuthFailure ["publickey"] False
pass (CryptoPassed x) = x
pass _ = undefined
with _ = Just pure
testActive07 :: TestTree
testActive07 = testCase "authenticate by other method (AuthNone)" $ do
let config = def { onAuthRequest = \_ _ _ -> pure Nothing }
(client, server) <- newDummyTransportPair
withAsync (withAuthentication config server sess with) $ \_ -> do
sendMessage client req0
receiveMessage client >>= assertEqual "res0" res0
sendMessage client req1
receiveMessage client >>= assertEqual "res1" res1
where
sess = SessionId mempty
req0 = ServiceRequest (Name "ssh-userauth")
res0 = ServiceAccept (Name "ssh-userauth")
req1 = UserAuthRequest (Name "fnord") (Name "ssh-connection") AuthNone
res1 = UserAuthFailure ["publickey"] False
with _ = Just pure