packages feed

oauth2-server-0.3.0.0: test/Web/OAuth2/MetadataSpec.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE OverloadedStrings #-}

module Web.OAuth2.MetadataSpec (tests) where

import Control.Concurrent.MVar (MVar, modifyMVar_)
import Data.Aeson (Value (..), eitherDecode)
import Data.Aeson.KeyMap qualified as KM
import Data.ByteString.Lazy qualified as LBS
import Data.Foldable (toList)
import Network.HTTP.Types (status200)
import Network.Wai (Application)
import Network.Wai.Test
import Test.Tasty
import Test.Tasty.HUnit
import Web.OAuth2.TestUtils
import Web.OAuth2.Types

tests :: TestTree
tests =
  testGroup
    "Metadata endpoint"
    [ returnsExpectedEndpoints
    , handlesExplicitPortGracefully
    ]

withApp :: (MVar (OAuthState TestUser) -> Application -> IO a) -> IO a
withApp action = do
  (stateVar, _ctx, app) <- createTestApplication
  action stateVar app

fetchMetadata :: Application -> IO Value
fetchMetadata app = do
  res <-
    runSession
      (srequest (SRequest (setPath defaultRequest "/.well-known/oauth-authorization-server") LBS.empty))
      app
  simpleStatus res @?= status200
  case eitherDecode (simpleBody res) of
    Left err -> assertFailure ("Failed to decode metadata: " <> err)
    Right val -> pure val

returnsExpectedEndpoints :: TestTree
returnsExpectedEndpoints = testCase "returns issuer and endpoints for default configuration" $
  withApp $ \_ app -> do
    val <- fetchMetadata app
    case val of
      Object obj -> do
        KM.lookup "issuer" obj @?= Just (String "http://localhost:8080")
        KM.lookup "authorization_endpoint" obj @?= Just (String "http://localhost:8080/authorize")
        KM.lookup "token_endpoint" obj @?= Just (String "http://localhost:8080/token")
        KM.lookup "registration_endpoint" obj @?= Just (String "http://localhost:8080/register")
        case KM.lookup "token_endpoint_auth_methods_supported" obj of
          Just (Array arr) ->
            toList arr @?= [String "none", String "client_secret_post"]
          _ -> assertFailure "token_endpoint_auth_methods_supported missing"
      _ -> assertFailure "metadata response not an object"

handlesExplicitPortGracefully :: TestTree
handlesExplicitPortGracefully = testCase "does not duplicate port when oauth_url already includes it" $
  withApp $ \stateVar app -> do
    modifyMVar_ stateVar $ \s -> pure s{oauth_url = "https://dpella.example:8443/", oauth_port = 8443}
    val <- fetchMetadata app
    case val of
      Object obj -> do
        KM.lookup "issuer" obj @?= Just (String "https://dpella.example:8443/")
        KM.lookup "authorization_endpoint" obj @?= Just (String "https://dpella.example:8443/authorize")
        KM.lookup "token_endpoint" obj @?= Just (String "https://dpella.example:8443/token")
      _ -> assertFailure "metadata response not an object"