Reading stdout and stderr of createProcess

For some time I’ve used this little utility to run a command with parameters and return stdout if the command exited successfully, or stdout and stderr if there was an error:

readRestOfHandle :: Handle -> IO String
readRestOfHandle h = do
    ineof  [String] -> IO (Either String String)
runShellCommand cmd args = do
    (Just _, Just hout, Just herr, h) <- createProcess (proc cmd args){ std_in = CreatePipe, std_out = CreatePipe, std_err = CreatePipe }

    stdOut <- readRestOfHandle hout
    stdErr <- readRestOfHandle herr

    exitCode  return $ Right stdOut
                     _           -> return $ Left $ stdOut ++ "nnn" ++ stdErr

Unfortunately this code is prone to deadlocking – I had this happen on a call to dcm2mnc. It ran dcm2mnc and then hung.

The fix was to use process-streaming which provides a wrapper for createProcess:

simpleSafeExecute :: PipingPolicy String a -> CreateProcess -> IO (Either String a)

And it’s straightforward to use it to get the stdout and stderr separately:

x <- simpleSafeExecute (pipeoe $ separated (surely B.toLazyM) (surely B.toLazyM)) (proc cmd args)

Here’s my commit where I switched to process-streaming: https://github.com/carlohamalainen/mytardis-rest/commit/7a97d2482abc7e5726ed003a480fc9a27ead7403.

A discussion on haskell-cafe where I found out about process-streaming: https://groups.google.com/d/msg/haskell-cafe/I1ROxgw7DIs/taKHeJJHiVkJ.

JWT verification using hs-jose and hs-jwt

Following up from a previous blog post, here is how to verify a JWT blob in the context of a Yesod site, using Fraser Tweedale’s hs-jwt package:

http://gist-it.appspot.com/github/carlohamalainen/rapid-connect-yesod-demo/blob/jose-and-hs-jwt/Handler/AuthJwt.hs?slice=84:139

Here’s the branch of my rapid connect demo that uses hs-jwt: https://github.com/carlohamalainen/rapid-connect-yesod-demo/tree/jose-and-hs-jwt.

Haskell Yesod AAF Rapid Connect demo

Federated identity authorisation is all the rage in the academic environment at the moment, and with good reason. Maintaining user accounts is a pain for devops staff, and end-users don’t need yet another username/password to forget.

In the past, hooking into the Australian Access Federation has required the configuration of a local Shibboleth Service Provider, which is not always an easy task (see for example mytardis-app-auth-aaf). Recently the AAF launched their Rapid Connect service. Instead of Shibboleth and SAML and other scary things, your application merely has to accept a HTTP POST on a pre-defined URL, which the Rapid Connect service passes a JSON Web Token (JWT) which you can verify using the pre-defined secret and an available JWT library.

I knocked up an example using a plain Django site which conveniently hooks into the Django auth module. All the work happens in views.py, in particular in the auth function.

Naturally I wanted to see how to do the same thing in Haskell. So here’s a working Yesod project that performs authorisation via Rapid Connect: https://github.com/carlohamalainen/rapid-connect-yesod-demo. The key file is Handler/AuthJwt.hs.

<!– In particular this function which accepts the HTTP POST request:

http://gist-it.appspot.com/github/carlohamalainen/rapid-connect-yesod-demo/blob/f4e138ec061dfafff8b9870e138bf371c4e2afda/Handler/AuthJwt.hs?slice=54:91

–>

I used the jwt package to decode and verify the JWT. Later I plan to try hs-jwt as well.

I think that the applicative style works well in this setting. I used to find the syntax jarring but now it is fine. The equivalent code in Python achieves a similar goal by wrapping the entire thing in a try/except block. So in some sense the Haskell code gives a finer control of the computed values (since Maybe has a Functor instance).