3
3
-- We authenticate clients using HTTP Basic or Digest authentication and we
4
4
-- authorise users based on membership of particular user groups.
5
5
--
6
- {-# LANGUAGE LambdaCase, PatternGuards #-}
6
+ {-# LANGUAGE LambdaCase, PatternGuards, NamedFieldPuns #-}
7
7
module Distribution.Server.Framework.Auth (
8
8
-- * Checking authorisation
9
9
guardAuthorised ,
@@ -39,6 +39,7 @@ import Distribution.Server.Framework.AuthCrypt
39
39
import Distribution.Server.Framework.AuthTypes
40
40
import Distribution.Server.Framework.Error
41
41
import Distribution.Server.Framework.HtmlFormWrapper (rqRealMethod )
42
+ import Distribution.Server.Framework.ServerEnv (ServerEnv , isRegularHost )
42
43
43
44
import Happstack.Server
44
45
@@ -77,9 +78,10 @@ adminRealm = RealmName "Hackage admin"
77
78
-- certain privileged actions.
78
79
--
79
80
guardAuthorised :: RealmName -> Users. Users -> [PrivilegeCondition ]
81
+ -> ServerEnv
80
82
-> ServerPartE UserId
81
- guardAuthorised realm users privconds = do
82
- (uid, _) <- guardAuthenticated realm users
83
+ guardAuthorised realm users privconds env = do
84
+ (uid, _) <- guardAuthenticated realm users env
83
85
guardPriviledged users uid privconds
84
86
return uid
85
87
@@ -93,22 +95,26 @@ guardAuthorised realm users privconds = do
93
95
-- It only checks the user is known, it does not imply that the user is
94
96
-- authorised to do anything in particular, see 'guardAuthorised'.
95
97
--
96
- guardAuthenticated :: RealmName -> Users. Users -> ServerPartE (UserId , UserInfo )
97
- guardAuthenticated realm users = do
98
- authres <- checkAuthenticated realm users
98
+ guardAuthenticated :: RealmName -> Users. Users -> ServerEnv -> ServerPartE (UserId , UserInfo )
99
+ guardAuthenticated realm users env = do
100
+ authres <- checkAuthenticated realm users env
99
101
case authres of
100
102
Left autherr -> throwError =<< authErrorResponse realm autherr
101
103
Right info -> return info
102
104
103
- checkAuthenticated :: ServerMonad m => RealmName -> Users. Users -> m (Either AuthError (UserId , UserInfo ))
104
- checkAuthenticated realm users = do
105
- req <- askRq
106
- return $ case getHeaderAuth req of
107
- Just (DigestAuth , ahdr) -> checkDigestAuth users ahdr req
108
- Just _ | plainHttp req -> Left InsecureAuthError
109
- Just (BasicAuth , ahdr) -> checkBasicAuth users realm ahdr
110
- Just (AuthToken , ahdr) -> checkTokenAuth users ahdr
111
- Nothing -> Left NoAuthError
105
+ checkAuthenticated :: ServerMonad m => RealmName -> Users. Users -> ServerEnv -> m (Either AuthError (UserId , UserInfo ))
106
+ checkAuthenticated realm users env = do
107
+ mbHostMismatch <- isRegularHost env
108
+ case mbHostMismatch of
109
+ Just (actualHost, oughtToBeHost) -> pure (Left BadHost { actualHost , oughtToBeHost })
110
+ Nothing -> do
111
+ req <- askRq
112
+ return $ case getHeaderAuth req of
113
+ Just (DigestAuth , ahdr) -> checkDigestAuth users ahdr req
114
+ Just _ | plainHttp req -> Left InsecureAuthError
115
+ Just (BasicAuth , ahdr) -> checkBasicAuth users realm ahdr
116
+ Just (AuthToken , ahdr) -> checkTokenAuth users ahdr
117
+ Nothing -> Left NoAuthError
112
118
where
113
119
getHeaderAuth :: Request -> Maybe (AuthType , BS. ByteString )
114
120
getHeaderAuth req =
@@ -424,6 +430,7 @@ data AuthError = NoAuthError
424
430
| UserStatusError UserId UserInfo
425
431
| PasswordMismatchError UserId UserInfo
426
432
| BadApiKeyError
433
+ | BadHost { actualHost :: BS. ByteString , oughtToBeHost :: String }
427
434
deriving Show
428
435
429
436
authErrorResponse :: MonadIO m => RealmName -> AuthError -> m ErrorResponse
@@ -449,6 +456,9 @@ authErrorResponse realm autherr = do
449
456
BadApiKeyError ->
450
457
ErrorResponse 401 [digestHeader] " Bad auth token" []
451
458
459
+ BadHost {} ->
460
+ ErrorResponse 401 [digestHeader] " Bad host" []
461
+
452
462
-- we don't want to leak info for the other cases, so same message for them all:
453
463
_ ->
454
464
ErrorResponse 401 [digestHeader] " Username or password incorrect" []
0 commit comments