Skip to content

Commit 56c7290

Browse files
fisxsupersven
authored andcommitted
wip
1 parent 6d0a367 commit 56c7290

File tree

6 files changed

+195
-9
lines changed

6 files changed

+195
-9
lines changed

libs/saml2-web-sso/saml2-web-sso.cabal

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ test-suite spec
208208
, asn1-parse >=0.9.5
209209
, asn1-types >=0.3.3
210210
, base >=4.12.0.0
211+
, base64
211212
, base64-bytestring >=1.0.0.2
212213
, binary >=0.8.6.0
213214
, bytestring >=0.10.8.2
@@ -236,7 +237,7 @@ test-suite spec
236237
, hspec-wai >=0.9.0
237238
, http-media >=0.8.0.0
238239
, http-types >=0.12.3
239-
, hxt >=9.3.1.18
240+
, hxt
240241
, imports
241242
, lens >=4.17.1
242243
, lens-datetime >=0.3
@@ -263,6 +264,7 @@ test-suite spec
263264
, types-common
264265
, uniplate >=1.6.12
265266
, uri-bytestring >=0.3.2.2
267+
, utf8-string
266268
, uuid >=1.3.13
267269
, wai >=3.2.2.1
268270
, wai-extra >=3.0.28

libs/saml2-web-sso/src/SAML2/WebSSO/API.hs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ import SAML2.WebSSO.SP
4646
import SAML2.WebSSO.Servant
4747
import SAML2.WebSSO.Types
4848
import SAML2.WebSSO.XML
49+
import SAML2.XML qualified as HS
4950
import Servant.API as Servant hiding (URI (..))
5051
import Servant.Multipart
5152
import Servant.Server
@@ -56,6 +57,7 @@ import Text.XML
5657
import Text.XML.Cursor
5758
import Text.XML.DSig
5859
import Text.XML.HXT.Core (XmlTree)
60+
import Text.XML.HXT.DOM.TypeDefs qualified as HS
5961
import URI.ByteString
6062

6163
----------------------------------------------------------------------
@@ -224,12 +226,16 @@ simpleVerifyAuthnResponse creds raw = do
224226
allVerifies :: forall m err. (MonadError (Error err) m) => NonEmpty SignCreds -> LBS -> NonEmpty String -> m (NonEmpty Assertion)
225227
allVerifies creds raw nodeids = do
226228
let workArounds = verifyADFS creds raw nodeids
227-
xmls <- case verify creds raw `mapM` nodeids of
229+
xmls :: NonEmpty XmlTree <- case verify creds raw `mapM` nodeids of
228230
Right assertions -> pure assertions
229231
Left err -> case workArounds of
230232
Right ws -> pure ws
231233
Left _ -> throwError . BadSamlResponseInvalidSignature $ cs err
232-
(renderVerifyErrorHack . parseFromXmlTree) `mapM` xmls
234+
-- here, xmls still contains correctly utf8-encoded display name:
235+
-- () <- error $ "********************************* " <> show xmls
236+
result <- (renderVerifyErrorHack . parseFromXmlTree) `mapM` xmls -- CRASH!!!
237+
-- () <- error "********************************* [not reached]"
238+
pure result
233239
where
234240
-- (there must be a better way for this, but where?)
235241
renderVerifyErrorHack :: forall m' err' a. (MonadError (Error err') m') => Either String a -> m' a

libs/saml2-web-sso/src/SAML2/WebSSO/Test/Util/Misc.hs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ module SAML2.WebSSO.Test.Util.Misc where
66
import Control.Monad
77
import Control.Monad.IO.Class
88
import Data.ByteString.Base64.Lazy qualified as EL (encode)
9+
import Data.ByteString.Lazy qualified as LBS
910
import Data.EitherR
1011
import Data.Generics.Uniplate.Data
1112
import Data.List (sort)
@@ -35,6 +36,13 @@ readSampleIO fpath =
3536
LT.readFile $
3637
$(fileRelativeToProject "test/samples") </> fpath
3738

39+
readSampleIOLBS :: (MonadIO m) => FilePath -> m LBS
40+
readSampleIOLBS fpath =
41+
liftIO
42+
$ LBS.readFile
43+
$ $(fileRelativeToProject "test/samples")
44+
</> fpath
45+
3846
doesSampleExistIO :: (MonadIO m) => FilePath -> m Bool
3947
doesSampleExistIO fpath =
4048
liftIO $

libs/saml2-web-sso/src/SAML2/WebSSO/XML.hs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import Control.Exception (SomeException)
3030
import Control.Lens hiding (element)
3131
import Control.Monad
3232
import Control.Monad.Except
33+
import Data.ByteString.Lazy qualified as LBS
3334
import Data.CaseInsensitive (CI)
3435
import Data.CaseInsensitive qualified as CI
3536
import Data.EitherR
@@ -60,6 +61,7 @@ import SAML2.XML qualified as HS
6061
import SAML2.XML qualified as HX
6162
import SAML2.XML.Schema.Datatypes qualified as HX (Boolean, Duration, UnsignedShort)
6263
import SAML2.XML.Signature.Types qualified as HX (Signature)
64+
import System.IO.Unsafe
6365
import Text.Hamlet.XML
6466
import Text.XML
6567
import Text.XML.Cursor
@@ -104,9 +106,15 @@ renderToDocument = mkDocument . renderRoot
104106
parseFromDocument :: (HasXML a, MonadError String m) => Document -> m a
105107
parseFromDocument doc = parse [NodeElement $ documentRoot doc]
106108

107-
parseFromXmlTree :: (MonadError String m, HasXML a) => XmlTree -> m a
109+
-- raw: "R\259zvan Ioan BIBAR\538" UTF16
110+
-- x: "R\ETXzvan Ioan BIBAR\SUB"
111+
112+
parseFromXmlTree :: (MonadError String m, HasXML a, Show a) => XmlTree -> m a
108113
parseFromXmlTree raw = do
109-
doc <- decode . decodeUtf8 $ HX.docToXMLWithRoot raw
114+
let x = HX.docToXMLWithRoot raw
115+
() <- error $ "************** [1]" <> show (raw, x) -- TODO: only x contains broken display name, so it's HX.docToXMLWithRoot :-(
116+
doc :: Document <- decode . decodeUtf8 $ HX.docToXMLWithRoot raw
117+
() <- error $ "************** CRASHED"
110118
parseFromDocument doc
111119

112120
-- FUTUREWORK: perhaps we want to split this up: HasXML (for nameSpaces), and HasXMLParse, HasXMLRender,

libs/saml2-web-sso/test/Test/SAML2/WebSSO/APISpec.hs

Lines changed: 57 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,25 @@ module Test.SAML2.WebSSO.APISpec
66
)
77
where
88

9+
import Codec.Binary.UTF8.String qualified as UTF8
910
import Control.Concurrent.MVar
1011
import Control.Exception (SomeException, try)
1112
import Control.Lens
1213
import Control.Monad
1314
import Control.Monad.IO.Class
15+
import Data.ByteString qualified as SBS
1416
import Data.ByteString.Base64.Lazy qualified as EL (decodeLenient, encode)
17+
import Data.ByteString.Lazy qualified as LBS
18+
import Data.ByteString.Lazy.Char8 qualified as LBSC8
19+
import Data.ByteString.Lazy.UTF8 qualified as LBSUTF8
1520
import Data.Either
1621
import Data.EitherR
1722
import Data.List.NonEmpty (NonEmpty ((:|)))
1823
import Data.Map qualified as Map
19-
import Data.Maybe (maybeToList)
24+
import Data.Maybe
2025
import Data.String.Conversions
26+
import Data.Text.Lazy.Encoding as LT
27+
import Data.Tree.NTree.TypeDefs as HXT
2128
import Data.UUID
2229
import Data.Yaml qualified as Yaml
2330
import Network.Wai.Test
@@ -26,14 +33,17 @@ import SAML2.WebSSO
2633
import SAML2.WebSSO.API.Example (RequestStore)
2734
import SAML2.WebSSO.Test.MockResponse
2835
import SAML2.WebSSO.Test.Util
36+
import SAML2.XML qualified as HSAML2
2937
import Servant
3038
import Test.Hspec hiding (pending)
3139
import Test.Hspec.Wai
3240
import Test.Hspec.Wai.Matcher
3341
import Text.XML as XML
42+
import Text.XML.HXT.DOM.ShowXml as HXT
43+
import Text.XML.HXT.DOM.TypeDefs as HXT
3444
import URI.ByteString.QQ
3545

36-
spec :: Spec
46+
spec :: (HasCallStack) => Spec
3747
spec = describe "API" $ do
3848
describe "base64 encoding" $ do
3949
describe "compatible with /usr/bin/env base64" $ do
@@ -327,10 +337,11 @@ spec = describe "API" $ do
327337
-- * onelogin
328338
-- * jives [https://community.jivesoftware.com/docs/DOC-240217#jive_content_id_IdP_Metadata]
329339

330-
focus . describe "simpleVerifyAuthnResponse, second attempt" $ do
340+
describe "simpleVerifyAuthnResponse, second attempt" $ do
331341
let check :: FilePath -> FilePath -> Expectation
332342
check metaFile respFile = do
333-
resp :: LBS <- cs <$> readSampleIO respFile
343+
resp :: LBS <- readSampleIOLBS respFile
344+
-- () <- error $ show resp -- "R\196\131zvan Ioan BIBAR\200\154" (UTF8!)
334345
assertions <- liftIO $ do
335346
idpCfg :: IdPConfig_ <- do
336347
raw :: LBS <- cs <$> readSampleIO metaFile
@@ -347,3 +358,45 @@ spec = describe "API" $ do
347358

348359
it "works" $ do
349360
check "microsoft-azure-utf8-issue-metadata.base64" "microsoft-azure-utf8-issue-authentication-request.base64"
361+
362+
-- hxt uses Char8.pack, which won't work on unicode strings.
363+
364+
focus . it "hxt bug?" $ do
365+
let nope1 :: LBS.ByteString = HXT.xshowBlob [NTree (XText payloadString) []]
366+
nope2 :: LBS.ByteString = LBSC8.pack payloadString
367+
nope3 :: LBS.ByteString = LBSUTF8.fromString payloadString
368+
yeah1 :: LBS.ByteString = LBS.pack bs
369+
370+
-- 0xC4=196, 0x83=131, 0xC8 = 200, 0x9A = 154
371+
-- ă -> 0xC4 0x83 (utf-8), 0x0103 (utf-16)
372+
-- Ț -> 0xC8 0x9A (utf-8), 0x021A (utf-16)
373+
bs = [0xC4, 0x83, 0xC8, 0x9A]
374+
payloadLBS :: LBS.ByteString = LBS.pack bs
375+
payloadString :: String = "ăȚ"
376+
utf8String = UTF8.encodeString payloadString
377+
378+
print (payloadLBS, payloadString, nope1, nope2, nope3)
379+
print (LBS.unpack payloadLBS, LBS.unpack nope1, LBS.unpack nope2, (LBS.unpack . LBSC8.pack) utf8String, LBS.unpack nope3)
380+
-- print ((LB.toString . LBS.toString) nope1, (LB.toString . LBS.toStrict) nope2)
381+
382+
LBS.writeFile "/tmp/x" payloadLBS
383+
-- <>) . LT.encodeUtf8) <$> LT.decodeUtf8' nope1)
384+
LBS.unpack nope2 `shouldBe` bs
385+
nope1 `shouldSatisfy` (SBS.isValidUtf8 . LBSC8.toStrict)
386+
nope2 `shouldSatisfy` (SBS.isValidUtf8 . LBSC8.toStrict)
387+
nope1 `shouldBe` "\x0103\x021a"
388+
nope2 `shouldBe` "\x0103\x021a"
389+
390+
it "parseFromXmlTree" $ do
391+
resp :: LBS <- cs <$> readSampleIO "microsoft-azure-utf8-issue-authentication-request.base64"
392+
let tree :: Maybe (NTree XNode) = HSAML2.xmlToDoc resp
393+
liftIO $ print resp
394+
liftIO $ print tree
395+
let result :: Either String AuthnResponse = parseFromXmlTree (fromJust tree)
396+
liftIO $ print result
397+
False `shouldBe` True
398+
399+
it "HSAML2.docToXMLWithRoot" $ do
400+
let x = "<samlp:Response ID=\"ăȚ\"></samlp:Response>\n"
401+
y = HSAML2.docToXMLWithRoot (HXT.NTree (HXT.XText x) [])
402+
y `shouldBe` x

0 commit comments

Comments
 (0)