Support IntermediateResponse

This commit is contained in:
Matvey Aksenov 2015-04-04 11:07:00 +00:00
parent 273c29e30a
commit 9ab5760b8e
5 changed files with 59 additions and 19 deletions

View File

@ -20,7 +20,7 @@ Modify DN Operation | 4.9 | ✔
Compare Operation | 4.10 | ✔ Compare Operation | 4.10 | ✔
Abandon Operation | 4.11 | ✘ Abandon Operation | 4.11 | ✘
Extended Operation | 4.12 | ✔ Extended Operation | 4.12 | ✔
IntermediateResponse Message | 4.13 | IntermediateResponse Message | 4.13 |
StartTLS Operation | 4.14 | ✔† StartTLS Operation | 4.14 | ✔†
LDAP over TLS | - | ✔ LDAP over TLS | - | ✔

View File

@ -294,9 +294,26 @@ AddResponse ::= [APPLICATION 9] LDAPResult
DelResponse ::= [APPLICATION 11] LDAPResult DelResponse ::= [APPLICATION 11] LDAPResult
@ @
@
ModifyDNResponse ::= [APPLICATION 13] LDAPResult
@
@ @
CompareResponse ::= [APPLICATION 15] LDAPResult CompareResponse ::= [APPLICATION 15] LDAPResult
@ @
@
ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
COMPONENTS OF LDAPResult,
responseName [10] LDAPOID OPTIONAL,
responseValue [11] OCTET STRING OPTIONAL }
@
@
IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
responseName [0] LDAPOID OPTIONAL,
responseValue [1] OCTET STRING OPTIONAL }
@
-} -}
instance FromAsn1 ProtocolServerOp where instance FromAsn1 ProtocolServerOp where
fromAsn1 = asum fromAsn1 = asum
@ -326,6 +343,15 @@ instance FromAsn1 ProtocolServerOp where
return s return s
Asn1.End (Asn1.Container Asn1.Application 24) <- next Asn1.End (Asn1.Container Asn1.Application 24) <- next
return (ExtendedResponse res (fmap LdapOid name) value) return (ExtendedResponse res (fmap LdapOid name) value)
, do
Asn1.Start (Asn1.Container Asn1.Application 25) <- next
name <- optional fromAsn1
value <- optional $ do
Asn1.OctetString s <- next
return s
Asn1.End (Asn1.Container Asn1.Application 25) <- next
return (IntermediateResponse name value)
] ]
where where
app l = do app l = do

View File

@ -372,11 +372,11 @@ MatchingRuleAssertion ::= SEQUENCE {
@ @
-} -}
instance ToAsn1 MatchingRuleAssertion where instance ToAsn1 MatchingRuleAssertion where
toAsn1 (MatchingRuleAssertion mmr mad (AssertionValue av) _) = (fold toAsn1 (MatchingRuleAssertion mmr mad (AssertionValue av) _) = fold
[ maybe mempty f mmr [ maybe mempty f mmr
, maybe mempty g mad , maybe mempty g mad
, other Asn1.Context 3 av , other Asn1.Context 3 av
]) ]
where where
f (MatchingRuleId (LdapString x)) = other Asn1.Context 1 (Text.encodeUtf8 x) f (MatchingRuleId (LdapString x)) = other Asn1.Context 1 (Text.encodeUtf8 x)
g (AttributeDescription (LdapString x)) = other Asn1.Context 2 (Text.encodeUtf8 x) g (AttributeDescription (LdapString x)) = other Asn1.Context 2 (Text.encodeUtf8 x)

View File

@ -38,6 +38,7 @@ data ProtocolServerOp =
| ModifyDnResponse LdapResult | ModifyDnResponse LdapResult
| CompareResponse LdapResult | CompareResponse LdapResult
| ExtendedResponse LdapResult (Maybe LdapOid) (Maybe ByteString) | ExtendedResponse LdapResult (Maybe LdapOid) (Maybe ByteString)
| IntermediateResponse (Maybe LdapOid) (Maybe ByteString)
deriving (Show, Eq, Ord) deriving (Show, Eq, Ord)
data AuthenticationChoice = Simple ByteString data AuthenticationChoice = Simple ByteString

View File

@ -65,7 +65,7 @@ import qualified Data.ASN1.Encoding as Asn1
import qualified Data.ASN1.Error as Asn1 import qualified Data.ASN1.Error as Asn1
import qualified Data.ByteString as ByteString import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as ByteString.Lazy import qualified Data.ByteString.Lazy as ByteString.Lazy
import Data.Foldable (traverse_, asum) import Data.Foldable (asum)
import Data.Function (fix) import Data.Function (fix)
import Data.List.NonEmpty (NonEmpty((:|))) import Data.List.NonEmpty (NonEmpty((:|)))
import qualified Data.Map.Strict as Map import qualified Data.Map.Strict as Map
@ -98,6 +98,8 @@ import Ldap.Client.Delete (delete)
import Ldap.Client.Compare (compare) import Ldap.Client.Compare (compare)
import Ldap.Client.Extended (extended) import Ldap.Client.Extended (extended)
{-# ANN module "HLint: ignore Use first" #-}
newLdap :: IO Ldap newLdap :: IO Ldap
newLdap = Ldap newLdap = Ldap
@ -184,22 +186,33 @@ dispatch
-> TQueue (Type.LdapMessage Request) -> TQueue (Type.LdapMessage Request)
-> IO a -> IO a
dispatch Ldap { client } inq outq = dispatch Ldap { client } inq outq =
flip fix (Map.empty, Map.empty, 1) $ \loop (!got, !results, !counter) -> flip fix (Map.empty, 1) $ \loop (!req, !counter) ->
loop =<< atomically (asum loop =<< atomically (asum
[ do New new var <- readTQueue client [ do New new var <- readTQueue client
writeTQueue outq (Type.LdapMessage (Type.Id counter) new Nothing) writeTQueue outq (Type.LdapMessage (Type.Id counter) new Nothing)
return (got, Map.insert (Type.Id counter) var results, counter + 1) return (Map.insert (Type.Id counter) ([], var) req, counter + 1)
, do Type.LdapMessage mid op _ <- readTQueue inq , do Type.LdapMessage mid op _
case op of <- readTQueue inq
Type.SearchResultEntry {} -> res <- case op of
return (Map.insertWith (++) mid [op] got, results, counter) Type.BindResponse {} -> done mid op req
Type.SearchResultReference {} -> Type.SearchResultEntry {} -> saveUp mid op req
return (got, results, counter) Type.SearchResultReference {} -> return req
Type.SearchResultDone {} -> do Type.SearchResultDone {} -> done mid op req
let stack = Map.findWithDefault [] mid got Type.ModifyResponse {} -> done mid op req
traverse_ (\var -> putTMVar var (op :| stack)) (Map.lookup mid results) Type.AddResponse {} -> done mid op req
return (Map.delete mid got, Map.delete mid results, counter) Type.DeleteResponse {} -> done mid op req
_ -> do Type.ModifyDnResponse {} -> done mid op req
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results) Type.CompareResponse {} -> done mid op req
return (Map.delete mid got, Map.delete mid results, counter) Type.ExtendedResponse {} -> done mid op req
Type.IntermediateResponse {} -> saveUp mid op req
return (res, counter)
]) ])
where
saveUp mid op res =
return (Map.adjust (\(stack, var) -> (op : stack, var)) mid res)
done mid op req =
case Map.lookup mid req of
Nothing -> return req
Just (stack, var) -> do
putTMVar var (op :| stack)
return (Map.delete mid req)