{"action":"created","comment":{"url":"https://api.github.com/repos/haskell-servant/servant/pulls/comments/36882815","id":36882815,"diff_hunk":"@@ -0,0 +1,107 @@\n+{-# LANGUAGE CPP                 #-}\n+{-# LANGUAGE DataKinds           #-}\n+{-# LANGUAGE OverloadedStrings   #-}\n+{-# LANGUAGE ScopedTypeVariables #-}\n+{-# LANGUAGE TypeFamilies        #-}\n+\n+module Servant.Server.Internal.Authentication\n+( AuthProtected (..)\n+, AuthData (..)\n+, AuthHandlers (AuthHandlers, onMissingAuthData, onUnauthenticated)\n+, basicAuthLax\n+, basicAuthStrict\n+, laxProtect\n+, strictProtect\n+        ) where\n+\n+import           Control.Monad              (guard)\n+import qualified Data.ByteString            as B\n+import           Data.ByteString.Base64     (decodeLenient)\n+#if !MIN_VERSION_base(4,8,0)\n+import           Data.Monoid                ((<>), mempty)\n+#else\n+import           Data.Monoid                ((<>))\n+#endif\n+import           Data.Proxy                 (Proxy (Proxy))\n+import           Data.String                (fromString)\n+import           Data.Word8                 (isSpace, toLower, _colon)\n+import           GHC.TypeLits               (KnownSymbol, symbolVal)\n+import           Network.HTTP.Types.Status  (status401)\n+import           Network.Wai                (Request, Response, requestHeaders,\n+                                             responseBuilder)\n+import           Servant.API.Authentication (AuthPolicy (Strict, Lax),\n+                                             AuthProtected,\n+                                             BasicAuth (BasicAuth))\n+\n+-- | Class to represent the ability to extract authentication-related\n+-- data from a 'Request' object.\n+class AuthData a where\n+    authData :: Request -> Maybe a\n+\n+-- | handlers to deal with authentication failures.\n+data AuthHandlers authData = AuthHandlers\n+    {   -- we couldn't find the right type of auth data (or any, for that matter)\n+        onMissingAuthData :: IO Response\n+    ,\n+        -- we found the right type of auth data in the request but the check failed\n+        onUnauthenticated :: authData -> IO Response\n+    }\n+\n+-- | concrete type to provide when in 'Strict' mode.\n+data instance AuthProtected authData usr subserver 'Strict =\n+    AuthProtectedStrict { checkAuthStrict :: authData -> IO (Maybe usr)\n+                        , authHandlers :: AuthHandlers authData\n+                        , subServerStrict :: subserver\n+                        }\n+\n+-- | concrete type to provide when in 'Lax' mode.\n+data instance AuthProtected authData usr subserver 'Lax =\n+    AuthProtectedLax { checkAuthLax :: authData -> IO (Maybe usr)\n+                     , subServerLax :: subserver\n+                     }\n+\n+-- | handy function to build an auth-protected bit of API with a Lax policy","path":"servant-server/src/Servant/Server/Internal/Authentication.hs","position":63,"original_position":63,"commit_id":"1205c790f4765c53ada1d24c398f7b38f07b7e11","original_commit_id":"1205c790f4765c53ada1d24c398f7b38f07b7e11","user":{"login":"alpmestan","id":119323,"avatar_url":"https://avatars.githubusercontent.com/u/119323?v=3","gravatar_id":"","url":"https://api.github.com/users/alpmestan","html_url":"https://github.com/alpmestan","followers_url":"https://api.github.com/users/alpmestan/followers","following_url":"https://api.github.com/users/alpmestan/following{/other_user}","gists_url":"https://api.github.com/users/alpmestan/gists{/gist_id}","starred_url":"https://api.github.com/users/alpmestan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/alpmestan/subscriptions","organizations_url":"https://api.github.com/users/alpmestan/orgs","repos_url":"https://api.github.com/users/alpmestan/repos","events_url":"https://api.github.com/users/alpmestan/events{/privacy}","received_events_url":"https://api.github.com/users/alpmestan/received_events","type":"User","site_admin":false},"body":"No, `'Lax'` is. It will link to `Lax`'s haddocks.","created_at":"2015-08-12T16:43:33Z","updated_at":"2015-08-12T16:43:33Z","html_url":"https://github.com/haskell-servant/servant/pull/185#discussion_r36882815","pull_request_url":"https://api.github.com/repos/haskell-servant/servant/pulls/185","_links":{"self":{"href":"https://api.github.com/repos/haskell-servant/servant/pulls/comments/36882815"},"html":{"href":"https://github.com/haskell-servant/servant/pull/185#discussion_r36882815"},"pull_request":{"href":"https://api.github.com/repos/haskell-servant/servant/pulls/185"}}},"pull_request":{"url":"https://api.github.com/repos/haskell-servant/servant/pulls/185","id":41963473,"html_url":"https://github.com/haskell-servant/servant/pull/185","diff_url":"https://github.com/haskell-servant/servant/pull/185.diff","patch_url":"https://github.com/haskell-servant/servant/pull/185.patch","issue_url":"https://api.github.com/repos/haskell-servant/servant/issues/185","number":185,"state":"open","locked":false,"title":"Authentication","user":{"login":"aaronlevin","id":1580060,"avatar_url":"https://avatars.githubusercontent.com/u/1580060?v=3","gravatar_id":"","url":"https://api.github.com/users/aaronlevin","html_url":"https://github.com/aaronlevin","followers_url":"https://api.github.com/users/aaronlevin/followers","following_url":"https://api.github.com/users/aaronlevin/following{/other_user}","gists_url":"https://api.github.com/users/aaronlevin/gists{/gist_id}","starred_url":"https://api.github.com/users/aaronlevin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaronlevin/subscriptions","organizations_url":"https://api.github.com/users/aaronlevin/orgs","repos_url":"https://api.github.com/users/aaronlevin/repos","events_url":"https://api.github.com/users/aaronlevin/events{/privacy}","received_events_url":"https://api.github.com/users/aaronlevin/received_events","type":"User","site_admin":false},"body":"This implements the initial ideas of our Authentication framework, including a simple example of how it's used for `Basic` authentication.\r\n\r\nThe basic design is outlined here: https://github.com/haskell-servant/servant/issues/70#issuecomment-122256550 \r\n\r\nMost of the changes are additive. However, we've added a new constructor to `RouteMismatch` that holds a generic `Response` object. This required the removal of both the `Eq` and `Ord` instances from `RouteMismatch`. This wasn't too destructive, but is probably the only controversial change (aside from design choices for authentication itself).","created_at":"2015-08-09T01:09:42Z","updated_at":"2015-08-12T16:43:33Z","closed_at":null,"merged_at":null,"merge_commit_sha":"8babf741329363b461e389812f1c84c755e04dcb","assignee":null,"milestone":null,"commits_url":"https://api.github.com/repos/haskell-servant/servant/pulls/185/commits","review_comments_url":"https://api.github.com/repos/haskell-servant/servant/pulls/185/comments","review_comment_url":"https://api.github.com/repos/haskell-servant/servant/pulls/comments{/number}","comments_url":"https://api.github.com/repos/haskell-servant/servant/issues/185/comments","statuses_url":"https://api.github.com/repos/haskell-servant/servant/statuses/1205c790f4765c53ada1d24c398f7b38f07b7e11","head":{"label":"aaronlevin:auth","ref":"auth","sha":"1205c790f4765c53ada1d24c398f7b38f07b7e11","user":{"login":"aaronlevin","id":1580060,"avatar_url":"https://avatars.githubusercontent.com/u/1580060?v=3","gravatar_id":"","url":"https://api.github.com/users/aaronlevin","html_url":"https://github.com/aaronlevin","followers_url":"https://api.github.com/users/aaronlevin/followers","following_url":"https://api.github.com/users/aaronlevin/following{/other_user}","gists_url":"https://api.github.com/users/aaronlevin/gists{/gist_id}","starred_url":"https://api.github.com/users/aaronlevin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaronlevin/subscriptions","organizations_url":"https://api.github.com/users/aaronlevin/orgs","repos_url":"https://api.github.com/users/aaronlevin/repos","events_url":"https://api.github.com/users/aaronlevin/events{/privacy}","received_events_url":"https://api.github.com/users/aaronlevin/received_events","type":"User","site_admin":false},"repo":{"id":35446107,"name":"servant","full_name":"aaronlevin/servant","owner":{"login":"aaronlevin","id":1580060,"avatar_url":"https://avatars.githubusercontent.com/u/1580060?v=3","gravatar_id":"","url":"https://api.github.com/users/aaronlevin","html_url":"https://github.com/aaronlevin","followers_url":"https://api.github.com/users/aaronlevin/followers","following_url":"https://api.github.com/users/aaronlevin/following{/other_user}","gists_url":"https://api.github.com/users/aaronlevin/gists{/gist_id}","starred_url":"https://api.github.com/users/aaronlevin/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/aaronlevin/subscriptions","organizations_url":"https://api.github.com/users/aaronlevin/orgs","repos_url":"https://api.github.com/users/aaronlevin/repos","events_url":"https://api.github.com/users/aaronlevin/events{/privacy}","received_events_url":"https://api.github.com/users/aaronlevin/received_events","type":"User","site_admin":false},"private":false,"html_url":"https://github.com/aaronlevin/servant","description":"Main repository for the servant libraries. Web API combinators, with servers, clients and documentation","fork":true,"url":"https://api.github.com/repos/aaronlevin/servant","forks_url":"https://api.github.com/repos/aaronlevin/servant/forks","keys_url":"https://api.github.com/repos/aaronlevin/servant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/aaronlevin/servant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/aaronlevin/servant/teams","hooks_url":"https://api.github.com/repos/aaronlevin/servant/hooks","issue_events_url":"https://api.github.com/repos/aaronlevin/servant/issues/events{/number}","events_url":"https://api.github.com/repos/aaronlevin/servant/events","assignees_url":"https://api.github.com/repos/aaronlevin/servant/assignees{/user}","branches_url":"https://api.github.com/repos/aaronlevin/servant/branches{/branch}","tags_url":"https://api.github.com/repos/aaronlevin/servant/tags","blobs_url":"https://api.github.com/repos/aaronlevin/servant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/aaronlevin/servant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/aaronlevin/servant/git/refs{/sha}","trees_url":"https://api.github.com/repos/aaronlevin/servant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/aaronlevin/servant/statuses/{sha}","languages_url":"https://api.github.com/repos/aaronlevin/servant/languages","stargazers_url":"https://api.github.com/repos/aaronlevin/servant/stargazers","contributors_url":"https://api.github.com/repos/aaronlevin/servant/contributors","subscribers_url":"https://api.github.com/repos/aaronlevin/servant/subscribers","subscription_url":"https://api.github.com/repos/aaronlevin/servant/subscription","commits_url":"https://api.github.com/repos/aaronlevin/servant/commits{/sha}","git_commits_url":"https://api.github.com/repos/aaronlevin/servant/git/commits{/sha}","comments_url":"https://api.github.com/repos/aaronlevin/servant/comments{/number}","issue_comment_url":"https://api.github.com/repos/aaronlevin/servant/issues/comments{/number}","contents_url":"https://api.github.com/repos/aaronlevin/servant/contents/{+path}","compare_url":"https://api.github.com/repos/aaronlevin/servant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/aaronlevin/servant/merges","archive_url":"https://api.github.com/repos/aaronlevin/servant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/aaronlevin/servant/downloads","issues_url":"https://api.github.com/repos/aaronlevin/servant/issues{/number}","pulls_url":"https://api.github.com/repos/aaronlevin/servant/pulls{/number}","milestones_url":"https://api.github.com/repos/aaronlevin/servant/milestones{/number}","notifications_url":"https://api.github.com/repos/aaronlevin/servant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/aaronlevin/servant/labels{/name}","releases_url":"https://api.github.com/repos/aaronlevin/servant/releases{/id}","created_at":"2015-05-11T19:45:16Z","updated_at":"2015-05-11T19:45:17Z","pushed_at":"2015-08-11T14:28:47Z","git_url":"git://github.com/aaronlevin/servant.git","ssh_url":"git@github.com:aaronlevin/servant.git","clone_url":"https://github.com/aaronlevin/servant.git","svn_url":"https://github.com/aaronlevin/servant","homepage":"http://haskell-servant.github.io/tutorial/#tutorial","size":3296,"stargazers_count":0,"watchers_count":0,"language":"Haskell","has_issues":false,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":0,"mirror_url":null,"open_issues_count":0,"forks":0,"open_issues":0,"watchers":0,"default_branch":"master"}},"base":{"label":"haskell-servant:master","ref":"master","sha":"1a27e46f5c7f47cd433bfa2bf8d9e4d7b2f737e6","user":{"login":"haskell-servant","id":10049283,"avatar_url":"https://avatars.githubusercontent.com/u/10049283?v=3","gravatar_id":"","url":"https://api.github.com/users/haskell-servant","html_url":"https://github.com/haskell-servant","followers_url":"https://api.github.com/users/haskell-servant/followers","following_url":"https://api.github.com/users/haskell-servant/following{/other_user}","gists_url":"https://api.github.com/users/haskell-servant/gists{/gist_id}","starred_url":"https://api.github.com/users/haskell-servant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/haskell-servant/subscriptions","organizations_url":"https://api.github.com/users/haskell-servant/orgs","repos_url":"https://api.github.com/users/haskell-servant/repos","events_url":"https://api.github.com/users/haskell-servant/events{/privacy}","received_events_url":"https://api.github.com/users/haskell-servant/received_events","type":"Organization","site_admin":false},"repo":{"id":27440142,"name":"servant","full_name":"haskell-servant/servant","owner":{"login":"haskell-servant","id":10049283,"avatar_url":"https://avatars.githubusercontent.com/u/10049283?v=3","gravatar_id":"","url":"https://api.github.com/users/haskell-servant","html_url":"https://github.com/haskell-servant","followers_url":"https://api.github.com/users/haskell-servant/followers","following_url":"https://api.github.com/users/haskell-servant/following{/other_user}","gists_url":"https://api.github.com/users/haskell-servant/gists{/gist_id}","starred_url":"https://api.github.com/users/haskell-servant/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/haskell-servant/subscriptions","organizations_url":"https://api.github.com/users/haskell-servant/orgs","repos_url":"https://api.github.com/users/haskell-servant/repos","events_url":"https://api.github.com/users/haskell-servant/events{/privacy}","received_events_url":"https://api.github.com/users/haskell-servant/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/haskell-servant/servant","description":"Main repository for the servant libraries. Web API combinators, with servers, clients and documentation","fork":false,"url":"https://api.github.com/repos/haskell-servant/servant","forks_url":"https://api.github.com/repos/haskell-servant/servant/forks","keys_url":"https://api.github.com/repos/haskell-servant/servant/keys{/key_id}","collaborators_url":"https://api.github.com/repos/haskell-servant/servant/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/haskell-servant/servant/teams","hooks_url":"https://api.github.com/repos/haskell-servant/servant/hooks","issue_events_url":"https://api.github.com/repos/haskell-servant/servant/issues/events{/number}","events_url":"https://api.github.com/repos/haskell-servant/servant/events","assignees_url":"https://api.github.com/repos/haskell-servant/servant/assignees{/user}","branches_url":"https://api.github.com/repos/haskell-servant/servant/branches{/branch}","tags_url":"https://api.github.com/repos/haskell-servant/servant/tags","blobs_url":"https://api.github.com/repos/haskell-servant/servant/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/haskell-servant/servant/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/haskell-servant/servant/git/refs{/sha}","trees_url":"https://api.github.com/repos/haskell-servant/servant/git/trees{/sha}","statuses_url":"https://api.github.com/repos/haskell-servant/servant/statuses/{sha}","languages_url":"https://api.github.com/repos/haskell-servant/servant/languages","stargazers_url":"https://api.github.com/repos/haskell-servant/servant/stargazers","contributors_url":"https://api.github.com/repos/haskell-servant/servant/contributors","subscribers_url":"https://api.github.com/repos/haskell-servant/servant/subscribers","subscription_url":"https://api.github.com/repos/haskell-servant/servant/subscription","commits_url":"https://api.github.com/repos/haskell-servant/servant/commits{/sha}","git_commits_url":"https://api.github.com/repos/haskell-servant/servant/git/commits{/sha}","comments_url":"https://api.github.com/repos/haskell-servant/servant/comments{/number}","issue_comment_url":"https://api.github.com/repos/haskell-servant/servant/issues/comments{/number}","contents_url":"https://api.github.com/repos/haskell-servant/servant/contents/{+path}","compare_url":"https://api.github.com/repos/haskell-servant/servant/compare/{base}...{head}","merges_url":"https://api.github.com/repos/haskell-servant/servant/merges","archive_url":"https://api.github.com/repos/haskell-servant/servant/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/haskell-servant/servant/downloads","issues_url":"https://api.github.com/repos/haskell-servant/servant/issues{/number}","pulls_url":"https://api.github.com/repos/haskell-servant/servant/pulls{/number}","milestones_url":"https://api.github.com/repos/haskell-servant/servant/milestones{/number}","notifications_url":"https://api.github.com/repos/haskell-servant/servant/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/haskell-servant/servant/labels{/name}","releases_url":"https://api.github.com/repos/haskell-servant/servant/releases{/id}","created_at":"2014-12-02T15:58:17Z","updated_at":"2015-08-12T09:50:49Z","pushed_at":"2015-08-12T08:46:49Z","git_url":"git://github.com/haskell-servant/servant.git","ssh_url":"git@github.com:haskell-servant/servant.git","clone_url":"https://github.com/haskell-servant/servant.git","svn_url":"https://github.com/haskell-servant/servant","homepage":"http://haskell-servant.github.io/tutorial/#tutorial","size":4540,"stargazers_count":198,"watchers_count":198,"language":"Haskell","has_issues":true,"has_downloads":true,"has_wiki":true,"has_pages":true,"forks_count":35,"mirror_url":null,"open_issues_count":38,"forks":35,"open_issues":38,"watchers":198,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/haskell-servant/servant/pulls/185"},"html":{"href":"https://github.com/haskell-servant/servant/pull/185"},"issue":{"href":"https://api.github.com/repos/haskell-servant/servant/issues/185"},"comments":{"href":"https://api.github.com/repos/haskell-servant/servant/issues/185/comments"},"review_comments":{"href":"https://api.github.com/repos/haskell-servant/servant/pulls/185/comments"},"review_comment":{"href":"https://api.github.com/repos/haskell-servant/servant/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/haskell-servant/servant/pulls/185/commits"},"statuses":{"href":"https://api.github.com/repos/haskell-servant/servant/statuses/1205c790f4765c53ada1d24c398f7b38f07b7e11"}}}}