haskell-servant / haskell-servant/servant-mock

Servant-mock and AuthProtect

Open
#1 3 comments 1 reaction 0 assignees View on GitHub
Dominant language
Haskell
Stars
19
Forks
10
PR merge metrics
No merged PRs in 30d

Description

_From @RocketPuppy on September 6, 2016 0:53_

While working on generating a mock server of my API (which is really cool now that I have it working), I ran into several issues regarding AuthProtect.

The first issue is simply that there isn't an instance for HasMock covering the AuthProtect combinator. Now that I've "implemented" one I think I'm starting to see why. The second issue is that authentication using AuthProtect is still done even in the mock servers. I have something working now but I'm not confident in it. I'll try and walk through my steps below.

Suppose an API like:

``` haskell
type API = AuthProtect "cookie-auth" AuthCookie :> Get '[JSON] SecretSauce
```

In order to mock I did the following:

``` haskell
api = Proxy :: Proxy API
type AppContext = '[ AuthHandler Request AuthCookie ]

context :: Context AppContext
context = (myAuthHandler :: AuthHandler Request AuthCookie) :. EmptyContext

mockServer = serveWithContext api context (mock api (Proxy :: AppContext))
```

`context` is used in the canonical implementation of the API to provide the authentication handler. The first problem I ran into was the lack of a `HasMock` instance. I came up with the following:

``` haskell
instance ( HasMock rest context
, HasServer rest context
, HasContextEntry context (AuthHandler Request (AuthServerData (AuthProtect sym)))
) =>
HasMock (AuthProtect (sym :: Symbol) :> rest) context where
mock _ context = \_ -> mock (Proxy :: Proxy rest) context
```

Which I'm not very happy with because it requires UndecidableInstances. The second problem I ran into, after I had that working, was that authentication still happens on the mock server. I'm on the fence as to whether this is actually a problem, but it was undesirable in my circumstances. I came up with the following solution:

``` haskell
mockAuthHandler :: (Arbitrary a) => AuthHandler Request a
mockAuthHandler = mkAuthHandler $ \ _ -> liftIO $ generate arbitrary

mockContext :: Context AppContext
mockContext = (mockAuthHandler :: AuthHandler Request AuthCookie) :. Context

-- and use mockContext in the mock server
mockServer = serveWithContext api mockContext (mock api (Proxy :: AppContext))
```

`mockAuthHandler` is always successful at authenticating a user.

Altogether this solution works, in that I can run a mock server and get arbitrary values from the endpoints. But I wouldn't say that servant-mock plays well with AuthProtect.

I'd be interested in better solutions than the one I hacked up here.

_Copied from original issue: haskell-servant/servant#596_

Contributor guide

No contributing guide indexed for this repository

Research direction

Start by examining the HasMock handling for AuthProtect and the mock server setup shown in the issue, including serveWithContext and the AuthHandler context. Determine whether mocks should bypass authentication or use a generated successful handler, then define the supported behavior and verify it with an AuthProtect API like the example.

Written by the indexing model from the issue text.

Assessment

Tech stack
haskell
Domain
api, backend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.