Support ModifyDN
This commit is contained in:
parent
ebccd8628f
commit
dd1a89d426
@ -15,7 +15,7 @@ Search Operation | 4.5 | ✔\*
|
|||||||
Modify Operation | 4.6 | ✔
|
Modify Operation | 4.6 | ✔
|
||||||
Add Operation | 4.7 | ✔
|
Add Operation | 4.7 | ✔
|
||||||
Delete Operation | 4.8 | ✔
|
Delete Operation | 4.8 | ✔
|
||||||
Modify DN Operation | 4.9 | ✘
|
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 | ✔
|
||||||
|
|||||||
@ -21,6 +21,9 @@ import qualified Data.Text.Encoding as Text
|
|||||||
|
|
||||||
import Ldap.Asn1.Type
|
import Ldap.Asn1.Type
|
||||||
|
|
||||||
|
{-# ANN module "HLint: ignore Use const" #-}
|
||||||
|
{-# ANN module "HLint: ignore Avoid lambda" #-}
|
||||||
|
|
||||||
|
|
||||||
class FromAsn1 a where
|
class FromAsn1 a where
|
||||||
fromAsn1 :: Parser [ASN1] a
|
fromAsn1 :: Parser [ASN1] a
|
||||||
@ -262,6 +265,7 @@ instance FromAsn1 ProtocolServerOp where
|
|||||||
, fmap ModifyResponse (app 7)
|
, fmap ModifyResponse (app 7)
|
||||||
, fmap AddResponse (app 9)
|
, fmap AddResponse (app 9)
|
||||||
, fmap DeleteResponse (app 11)
|
, fmap DeleteResponse (app 11)
|
||||||
|
, fmap ModifyDnResponse (app 13)
|
||||||
, fmap CompareResponse (app 15)
|
, fmap CompareResponse (app 15)
|
||||||
, do
|
, do
|
||||||
Asn1.Start (Asn1.Container Asn1.Application 24) <- next
|
Asn1.Start (Asn1.Container Asn1.Application 24) <- next
|
||||||
|
|||||||
@ -61,6 +61,12 @@ LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
|
|||||||
instance ToAsn1 LdapDn where
|
instance ToAsn1 LdapDn where
|
||||||
toAsn1 (LdapDn s) = toAsn1 s
|
toAsn1 (LdapDn s) = toAsn1 s
|
||||||
|
|
||||||
|
{- |
|
||||||
|
RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
|
||||||
|
-}
|
||||||
|
instance ToAsn1 RelativeLdapDn where
|
||||||
|
toAsn1 (RelativeLdapDn s) = toAsn1 s
|
||||||
|
|
||||||
{- |
|
{- |
|
||||||
AttributeDescription ::= LDAPString
|
AttributeDescription ::= LDAPString
|
||||||
-}
|
-}
|
||||||
@ -172,6 +178,12 @@ AddRequest ::= [APPLICATION 8] SEQUENCE {
|
|||||||
|
|
||||||
DelRequest ::= [APPLICATION 10] LDAPDN
|
DelRequest ::= [APPLICATION 10] LDAPDN
|
||||||
|
|
||||||
|
ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
|
||||||
|
entry LDAPDN,
|
||||||
|
newrdn RelativeLDAPDN,
|
||||||
|
deleteoldrdn BOOLEAN,
|
||||||
|
newSuperior [0] LDAPDN OPTIONAL }
|
||||||
|
|
||||||
CompareRequest ::= [APPLICATION 14] SEQUENCE {
|
CompareRequest ::= [APPLICATION 14] SEQUENCE {
|
||||||
entry LDAPDN,
|
entry LDAPDN,
|
||||||
ava AttributeValueAssertion }
|
ava AttributeValueAssertion }
|
||||||
@ -219,6 +231,15 @@ instance ToAsn1 ProtocolClientOp where
|
|||||||
application 8 (toAsn1 dn <> toAsn1 as)
|
application 8 (toAsn1 dn <> toAsn1 as)
|
||||||
toAsn1 (DeleteRequest (LdapDn (LdapString dn))) =
|
toAsn1 (DeleteRequest (LdapDn (LdapString dn))) =
|
||||||
other Asn1.Application 10 (Text.encodeUtf8 dn)
|
other Asn1.Application 10 (Text.encodeUtf8 dn)
|
||||||
|
toAsn1 (ModifyDnRequest dn rdn del new) =
|
||||||
|
application 12 (fold
|
||||||
|
[ toAsn1 dn
|
||||||
|
, toAsn1 rdn
|
||||||
|
, single (Asn1.Boolean del)
|
||||||
|
, maybe mempty
|
||||||
|
(\(LdapDn (LdapString dn')) -> other Asn1.Context 0 (Text.encodeUtf8 dn'))
|
||||||
|
new
|
||||||
|
])
|
||||||
toAsn1 (CompareRequest dn av) =
|
toAsn1 (CompareRequest dn av) =
|
||||||
application 14 (toAsn1 dn <> sequence (toAsn1 av))
|
application 14 (toAsn1 dn <> sequence (toAsn1 av))
|
||||||
toAsn1 (ExtendedRequest (LdapOid oid) mv) =
|
toAsn1 (ExtendedRequest (LdapOid oid) mv) =
|
||||||
|
|||||||
@ -19,10 +19,11 @@ data ProtocolClientOp =
|
|||||||
BindRequest Int8 LdapDn AuthenticationChoice
|
BindRequest Int8 LdapDn AuthenticationChoice
|
||||||
| UnbindRequest
|
| UnbindRequest
|
||||||
| SearchRequest LdapDn Scope DerefAliases Int32 Int32 Bool Filter AttributeSelection
|
| SearchRequest LdapDn Scope DerefAliases Int32 Int32 Bool Filter AttributeSelection
|
||||||
|
| ModifyRequest LdapDn [(Operation, PartialAttribute)]
|
||||||
| AddRequest LdapDn AttributeList
|
| AddRequest LdapDn AttributeList
|
||||||
| DeleteRequest LdapDn
|
| DeleteRequest LdapDn
|
||||||
|
| ModifyDnRequest LdapDn RelativeLdapDn Bool (Maybe LdapDn)
|
||||||
| CompareRequest LdapDn AttributeValueAssertion
|
| CompareRequest LdapDn AttributeValueAssertion
|
||||||
| ModifyRequest LdapDn [(Operation, PartialAttribute)]
|
|
||||||
| ExtendedRequest LdapOid (Maybe ByteString)
|
| ExtendedRequest LdapOid (Maybe ByteString)
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
@ -34,6 +35,7 @@ data ProtocolServerOp =
|
|||||||
| ModifyResponse LdapResult
|
| ModifyResponse LdapResult
|
||||||
| AddResponse LdapResult
|
| AddResponse LdapResult
|
||||||
| DeleteResponse LdapResult
|
| DeleteResponse LdapResult
|
||||||
|
| ModifyDnResponse LdapResult
|
||||||
| CompareResponse LdapResult
|
| CompareResponse LdapResult
|
||||||
| ExtendedResponse LdapResult (Maybe LdapOid) (Maybe ByteString)
|
| ExtendedResponse LdapResult (Maybe LdapOid) (Maybe ByteString)
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord)
|
||||||
@ -163,6 +165,9 @@ data PartialAttribute = PartialAttribute AttributeDescription [AttributeValue]
|
|||||||
newtype LdapDn = LdapDn LdapString
|
newtype LdapDn = LdapDn LdapString
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
|
newtype RelativeLdapDn = RelativeLdapDn LdapString
|
||||||
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
newtype ReferralUris = ReferralUris (NonEmpty Uri)
|
newtype ReferralUris = ReferralUris (NonEmpty Uri)
|
||||||
deriving (Show, Eq, Ord)
|
deriving (Show, Eq, Ord)
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
{-# LANGUAGE CPP #-}
|
{-# LANGUAGE CPP #-}
|
||||||
{-# LANGUAGE BangPatterns #-}
|
{-# LANGUAGE BangPatterns #-}
|
||||||
{-# LANGUAGE DeriveDataTypeable #-}
|
|
||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
module Ldap.Client
|
module Ldap.Client
|
||||||
( Host(..)
|
( Host(..)
|
||||||
@ -35,6 +34,9 @@ module Ldap.Client
|
|||||||
, add
|
, add
|
||||||
-- * Delete Operation
|
-- * Delete Operation
|
||||||
, delete
|
, delete
|
||||||
|
-- * ModifyDn Operation
|
||||||
|
, RelativeDn(..)
|
||||||
|
, modifyDn
|
||||||
-- * Compare Operation
|
-- * Compare Operation
|
||||||
, compare
|
, compare
|
||||||
-- * Extended Operation
|
-- * Extended Operation
|
||||||
@ -85,7 +87,7 @@ import Ldap.Client.Search
|
|||||||
, Filter(..)
|
, Filter(..)
|
||||||
, SearchEntry(..)
|
, SearchEntry(..)
|
||||||
)
|
)
|
||||||
import Ldap.Client.Modify (Operation(..), modify)
|
import Ldap.Client.Modify (Operation(..), modify, modifyDn)
|
||||||
import Ldap.Client.Add (add)
|
import Ldap.Client.Add (add)
|
||||||
import Ldap.Client.Delete (delete)
|
import Ldap.Client.Delete (delete)
|
||||||
import Ldap.Client.Compare (compare)
|
import Ldap.Client.Compare (compare)
|
||||||
@ -177,37 +179,22 @@ 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) -> do
|
flip fix (Map.empty, Map.empty, 1) $ \loop (!got, !results, !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 (got, Map.insert (Type.Id counter) var results, counter + 1)
|
||||||
, do Type.LdapMessage mid op _ <- readTQueue inq
|
, do Type.LdapMessage mid op _ <- readTQueue inq
|
||||||
case op of
|
case op of
|
||||||
Type.BindResponse {} -> do
|
Type.SearchResultEntry {} ->
|
||||||
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
|
|
||||||
return (Map.delete mid got, Map.delete mid results, counter)
|
|
||||||
Type.SearchResultEntry {} -> do
|
|
||||||
return (Map.insertWith (++) mid [op] got, results, counter)
|
return (Map.insertWith (++) mid [op] got, results, counter)
|
||||||
Type.SearchResultReference {} -> do
|
Type.SearchResultReference {} ->
|
||||||
return (got, results, counter)
|
return (got, results, counter)
|
||||||
Type.SearchResultDone {} -> do
|
Type.SearchResultDone {} -> do
|
||||||
let stack = Map.findWithDefault [] mid got
|
let stack = Map.findWithDefault [] mid got
|
||||||
traverse_ (\var -> putTMVar var (op :| stack)) (Map.lookup mid results)
|
traverse_ (\var -> putTMVar var (op :| stack)) (Map.lookup mid results)
|
||||||
return (Map.delete mid got, Map.delete mid results, counter)
|
return (Map.delete mid got, Map.delete mid results, counter)
|
||||||
Type.ModifyResponse {} -> do
|
_ -> do
|
||||||
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
|
|
||||||
return (Map.delete mid got, Map.delete mid results, counter)
|
|
||||||
Type.AddResponse {} -> do
|
|
||||||
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
|
|
||||||
return (Map.delete mid got, Map.delete mid results, counter)
|
|
||||||
Type.DeleteResponse {} -> do
|
|
||||||
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
|
|
||||||
return (Map.delete mid got, Map.delete mid results, counter)
|
|
||||||
Type.CompareResponse {} -> do
|
|
||||||
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
|
|
||||||
return (Map.delete mid got, Map.delete mid results, counter)
|
|
||||||
Type.ExtendedResponse {} -> do
|
|
||||||
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
|
traverse_ (\var -> putTMVar var (op :| [])) (Map.lookup mid results)
|
||||||
return (Map.delete mid got, Map.delete mid results, counter)
|
return (Map.delete mid got, Map.delete mid results, counter)
|
||||||
])
|
])
|
||||||
|
|||||||
@ -36,8 +36,8 @@ extendedAsyncSTM l oid mv =
|
|||||||
let req = extendedRequest oid mv in sendRequest l (extendedResult req) req
|
let req = extendedRequest oid mv in sendRequest l (extendedResult req) req
|
||||||
|
|
||||||
extendedRequest :: Oid -> Maybe ByteString -> Request
|
extendedRequest :: Oid -> Maybe ByteString -> Request
|
||||||
extendedRequest (Oid oid) mv =
|
extendedRequest (Oid oid) =
|
||||||
Type.ExtendedRequest (Type.LdapOid oid) mv
|
Type.ExtendedRequest (Type.LdapOid oid)
|
||||||
|
|
||||||
extendedResult :: Request -> Response -> Either ResponseError ()
|
extendedResult :: Request -> Response -> Either ResponseError ()
|
||||||
extendedResult req (Type.ExtendedResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
|
extendedResult req (Type.ExtendedResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn))
|
||||||
|
|||||||
@ -1,4 +1,3 @@
|
|||||||
{-# LANGUAGE BangPatterns #-}
|
|
||||||
{-# LANGUAGE DeriveDataTypeable #-}
|
{-# LANGUAGE DeriveDataTypeable #-}
|
||||||
{-# LANGUAGE NamedFieldPuns #-}
|
{-# LANGUAGE NamedFieldPuns #-}
|
||||||
module Ldap.Client.Internal
|
module Ldap.Client.Internal
|
||||||
@ -20,6 +19,7 @@ module Ldap.Client.Internal
|
|||||||
, raise
|
, raise
|
||||||
, sendRequest
|
, sendRequest
|
||||||
, Dn(..)
|
, Dn(..)
|
||||||
|
, RelativeDn(..)
|
||||||
, Password(..)
|
, Password(..)
|
||||||
, Attr(..)
|
, Attr(..)
|
||||||
, unAttr
|
, unAttr
|
||||||
@ -62,6 +62,9 @@ instance Functor Async where
|
|||||||
newtype Dn = Dn Text
|
newtype Dn = Dn Text
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
newtype RelativeDn = RelativeDn Text
|
||||||
|
deriving (Show, Eq)
|
||||||
|
|
||||||
newtype Oid = Oid ByteString
|
newtype Oid = Oid ByteString
|
||||||
deriving (Show, Eq)
|
deriving (Show, Eq)
|
||||||
|
|
||||||
|
|||||||
@ -4,6 +4,10 @@ module Ldap.Client.Modify
|
|||||||
, modifyEither
|
, modifyEither
|
||||||
, modifyAsync
|
, modifyAsync
|
||||||
, modifyAsyncSTM
|
, modifyAsyncSTM
|
||||||
|
, modifyDn
|
||||||
|
, modifyDnEither
|
||||||
|
, modifyDnAsync
|
||||||
|
, modifyDnAsyncSTM
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.STM (STM, atomically)
|
import Control.Monad.STM (STM, atomically)
|
||||||
@ -55,3 +59,33 @@ modifyResult req (Type.ModifyResponse (Type.LdapResult code (Type.LdapDn (Type.L
|
|||||||
| Type.Success <- code = Right ()
|
| Type.Success <- code = Right ()
|
||||||
| otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
|
| otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
|
||||||
modifyResult req res = Left (ResponseInvalid req res)
|
modifyResult req res = Left (ResponseInvalid req res)
|
||||||
|
|
||||||
|
|
||||||
|
modifyDn :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO ()
|
||||||
|
modifyDn l dn rdn del new =
|
||||||
|
raise =<< modifyDnEither l dn rdn del new
|
||||||
|
|
||||||
|
modifyDnEither :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Either ResponseError ())
|
||||||
|
modifyDnEither l dn rdn del new =
|
||||||
|
wait =<< modifyDnAsync l dn rdn del new
|
||||||
|
|
||||||
|
modifyDnAsync :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> IO (Async ())
|
||||||
|
modifyDnAsync l dn rdn del new =
|
||||||
|
atomically (modifyDnAsyncSTM l dn rdn del new)
|
||||||
|
|
||||||
|
modifyDnAsyncSTM :: Ldap -> Dn -> RelativeDn -> Bool -> Maybe Dn -> STM (Async ())
|
||||||
|
modifyDnAsyncSTM l dn rdn del new =
|
||||||
|
let req = modifyDnRequest dn rdn del new in sendRequest l (modifyDnResult req) req
|
||||||
|
|
||||||
|
modifyDnRequest :: Dn -> RelativeDn -> Bool -> Maybe Dn -> Request
|
||||||
|
modifyDnRequest (Dn dn) (RelativeDn rdn) del new =
|
||||||
|
Type.ModifyDnRequest (Type.LdapDn (Type.LdapString dn))
|
||||||
|
(Type.RelativeLdapDn (Type.LdapString rdn))
|
||||||
|
del
|
||||||
|
(fmap (\(Dn dn') -> Type.LdapDn (Type.LdapString dn')) new)
|
||||||
|
|
||||||
|
modifyDnResult :: Request -> Response -> Either ResponseError ()
|
||||||
|
modifyDnResult req (Type.ModifyDnResponse (Type.LdapResult code (Type.LdapDn (Type.LdapString dn)) (Type.LdapString msg) _) :| [])
|
||||||
|
| Type.Success <- code = Right ()
|
||||||
|
| otherwise = Left (ResponseErrorCode req code (Dn dn) msg)
|
||||||
|
modifyDnResult req res = Left (ResponseInvalid req res)
|
||||||
|
|||||||
@ -21,9 +21,9 @@ spec = do
|
|||||||
it "adds an entry" $ do
|
it "adds an entry" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l -> do
|
||||||
Ldap.add l vulpix
|
Ldap.add l vulpix
|
||||||
[ (Attr "cn", (NonEmpty.fromList ["vulpix"]))
|
[ (Attr "cn", NonEmpty.fromList ["vulpix"])
|
||||||
, (Attr "evolution", (NonEmpty.fromList ["0"]))
|
, (Attr "evolution", NonEmpty.fromList ["0"])
|
||||||
, (Attr "type", (NonEmpty.fromList ["fire"]))
|
, (Attr "type", NonEmpty.fromList ["fire"])
|
||||||
]
|
]
|
||||||
res <- go l (Attr "cn" := "vulpix")
|
res <- go l (Attr "cn" := "vulpix")
|
||||||
dns res `shouldBe` [vulpix]
|
dns res `shouldBe` [vulpix]
|
||||||
|
|||||||
@ -11,12 +11,12 @@ import SpecHelper (locally)
|
|||||||
spec :: Spec
|
spec :: Spec
|
||||||
spec = do
|
spec = do
|
||||||
it "binds as ‘admin’" $ do
|
it "binds as ‘admin’" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l ->
|
||||||
Ldap.bind l (Dn "cn=admin") (Password "secret")
|
Ldap.bind l (Dn "cn=admin") (Password "secret")
|
||||||
res `shouldBe` Right ()
|
res `shouldBe` Right ()
|
||||||
|
|
||||||
it "tries to bind as ‘admin’ with the wrong password, unsuccessfully" $ do
|
it "tries to bind as ‘admin’ with the wrong password, unsuccessfully" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l ->
|
||||||
Ldap.bind l (Dn "cn=admin") (Password "public")
|
Ldap.bind l (Dn "cn=admin") (Password "public")
|
||||||
res `shouldBe` Left
|
res `shouldBe` Left
|
||||||
(Ldap.ResponseError
|
(Ldap.ResponseError
|
||||||
@ -31,7 +31,7 @@ spec = do
|
|||||||
it "binds as ‘pikachu’" $ do
|
it "binds as ‘pikachu’" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l -> do
|
||||||
Ldap.bind l (Dn "cn=admin") (Password "secret")
|
Ldap.bind l (Dn "cn=admin") (Password "secret")
|
||||||
Ldap.SearchEntry udn _ : []
|
[Ldap.SearchEntry udn _]
|
||||||
<- Ldap.search l (Dn "o=localhost")
|
<- Ldap.search l (Dn "o=localhost")
|
||||||
(scope WholeSubtree)
|
(scope WholeSubtree)
|
||||||
(Attr "cn" := "pikachu")
|
(Attr "cn" := "pikachu")
|
||||||
|
|||||||
@ -26,7 +26,7 @@ spec = do
|
|||||||
res `shouldBe` Right ()
|
res `shouldBe` Right ()
|
||||||
|
|
||||||
it "tries to delete an non-existing entry, unsuccessfully" $ do
|
it "tries to delete an non-existing entry, unsuccessfully" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l ->
|
||||||
Ldap.delete l oddish
|
Ldap.delete l oddish
|
||||||
res `shouldBe` Left
|
res `shouldBe` Left
|
||||||
(Ldap.ResponseError
|
(Ldap.ResponseError
|
||||||
|
|||||||
@ -21,7 +21,7 @@ spec = do
|
|||||||
(Dn "")
|
(Dn "")
|
||||||
"0 not supported"))
|
"0 not supported"))
|
||||||
|
|
||||||
it "sends a startTLS request" $ do
|
it "sends a StartTLS request" $ do
|
||||||
res <- locally $ \l ->
|
res <- locally $ \l ->
|
||||||
Ldap.startTls l
|
Ldap.startTls l
|
||||||
res `shouldBe` Left
|
res `shouldBe` Left
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import Test.Hspec
|
|||||||
import qualified Ldap.Asn1.Type as Ldap.Type
|
import qualified Ldap.Asn1.Type as Ldap.Type
|
||||||
import Ldap.Client as Ldap
|
import Ldap.Client as Ldap
|
||||||
|
|
||||||
import SpecHelper (locally, charizard, pikachu)
|
import SpecHelper (locally, charizard, pikachu, raichu)
|
||||||
|
|
||||||
|
|
||||||
spec :: Spec
|
spec :: Spec
|
||||||
@ -30,7 +30,7 @@ spec = do
|
|||||||
res `shouldBe` Right ()
|
res `shouldBe` Right ()
|
||||||
|
|
||||||
it "tries to remove ‘pikachu’'s password, unsuccessfully" $ do
|
it "tries to remove ‘pikachu’'s password, unsuccessfully" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l ->
|
||||||
Ldap.modify l pikachu [Attr "password" `Delete` []]
|
Ldap.modify l pikachu [Attr "password" `Delete` []]
|
||||||
res `shouldBe` Left
|
res `shouldBe` Left
|
||||||
(ResponseError
|
(ResponseError
|
||||||
@ -45,7 +45,7 @@ spec = do
|
|||||||
(Dn "o=localhost")
|
(Dn "o=localhost")
|
||||||
"cannot delete password"))
|
"cannot delete password"))
|
||||||
|
|
||||||
context "add" $ do
|
context "add" $
|
||||||
it "can feed ‘charizard’" $ do
|
it "can feed ‘charizard’" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l -> do
|
||||||
[x] <- go l (Attr "cn" := "charizard")
|
[x] <- go l (Attr "cn" := "charizard")
|
||||||
@ -57,7 +57,7 @@ spec = do
|
|||||||
lookupAttr (Attr "type") y `shouldBe` Just ["fire", "flying", "fed"]
|
lookupAttr (Attr "type") y `shouldBe` Just ["fire", "flying", "fed"]
|
||||||
res `shouldBe` Right ()
|
res `shouldBe` Right ()
|
||||||
|
|
||||||
context "replace" $ do
|
context "replace" $
|
||||||
it "can put ‘charizard’ to sleep" $ do
|
it "can put ‘charizard’ to sleep" $ do
|
||||||
res <- locally $ \l -> do
|
res <- locally $ \l -> do
|
||||||
[x] <- go l (Attr "cn" := "charizard")
|
[x] <- go l (Attr "cn" := "charizard")
|
||||||
@ -69,5 +69,23 @@ spec = do
|
|||||||
lookupAttr (Attr "type") y `shouldBe` Just ["sleeping"]
|
lookupAttr (Attr "type") y `shouldBe` Just ["sleeping"]
|
||||||
res `shouldBe` Right ()
|
res `shouldBe` Right ()
|
||||||
|
|
||||||
|
context "modify dn" $
|
||||||
|
it "evolves ‘pikachu’ into ‘raichu’" $ do
|
||||||
|
res <- locally $ \l -> do
|
||||||
|
[] <- go l (Attr "cn" := "raichu")
|
||||||
|
|
||||||
|
Ldap.modifyDn l pikachu (RelativeDn "cn=raichu") False Nothing
|
||||||
|
Ldap.modify l raichu [Attr "evolution" `Replace` ["1"]]
|
||||||
|
|
||||||
|
[res] <- go l (Attr "cn" := "raichu")
|
||||||
|
res `shouldBe`
|
||||||
|
SearchEntry raichu
|
||||||
|
[ (Attr "cn", ["raichu"])
|
||||||
|
, (Attr "evolution", ["1"])
|
||||||
|
, (Attr "type", ["electric"])
|
||||||
|
, (Attr "password", ["i-choose-you"])
|
||||||
|
]
|
||||||
|
res `shouldBe` Right ()
|
||||||
|
|
||||||
lookupAttr :: Attr -> SearchEntry -> Maybe [ByteString]
|
lookupAttr :: Attr -> SearchEntry -> Maybe [ByteString]
|
||||||
lookupAttr a (SearchEntry _ as) = lookup a as
|
lookupAttr a (SearchEntry _ as) = lookup a as
|
||||||
|
|||||||
@ -17,6 +17,7 @@ module SpecHelper
|
|||||||
, metapod
|
, metapod
|
||||||
, butterfree
|
, butterfree
|
||||||
, pikachu
|
, pikachu
|
||||||
|
, raichu
|
||||||
, vulpix
|
, vulpix
|
||||||
, oddish
|
, oddish
|
||||||
) where
|
) where
|
||||||
@ -90,6 +91,9 @@ butterfree = Dn "cn=butterfree,o=localhost"
|
|||||||
pikachu :: Dn
|
pikachu :: Dn
|
||||||
pikachu = Dn "cn=pikachu,o=localhost"
|
pikachu = Dn "cn=pikachu,o=localhost"
|
||||||
|
|
||||||
|
raichu :: Dn
|
||||||
|
raichu = Dn "cn=raichu,o=localhost"
|
||||||
|
|
||||||
vulpix :: Dn
|
vulpix :: Dn
|
||||||
vulpix = Dn "cn=vulpix,o=localhost"
|
vulpix = Dn "cn=vulpix,o=localhost"
|
||||||
|
|
||||||
|
|||||||
15
test/ldap.js
15
test/ldap.js
@ -158,6 +158,19 @@ server.del('o=localhost', [], function(req, res, next) {
|
|||||||
return next(new ldapjs.NoSuchObjectError(req.dn.toString()));
|
return next(new ldapjs.NoSuchObjectError(req.dn.toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.modifyDN('o=localhost', [], function(req, res, next) {
|
||||||
|
for (var i = 0; i < pokemon.length; i++) {
|
||||||
|
if (req.dn.toString() === pokemon[i].dn) {
|
||||||
|
req.dn.rdns[0] = req.newRdn.rdns[0];
|
||||||
|
pokemon[i].dn = req.dn.toString();
|
||||||
|
pokemon[i].attributes.cn = req.newRdn.rdns[0].cn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
res.end();
|
||||||
|
return next();
|
||||||
|
});
|
||||||
|
|
||||||
server.compare('o=localhost', [], function(req, res, next) {
|
server.compare('o=localhost', [], function(req, res, next) {
|
||||||
for (var i = 0; i < pokemon.length; i++) {
|
for (var i = 0; i < pokemon.length; i++) {
|
||||||
if (req.dn.toString() === pokemon[i].dn) {
|
if (req.dn.toString() === pokemon[i].dn) {
|
||||||
@ -183,6 +196,6 @@ server.compare('o=localhost', [], function(req, res, next) {
|
|||||||
return next(new ldapjs.NoSuchObjectError(req.dn.toString()));
|
return next(new ldapjs.NoSuchObjectError(req.dn.toString()));
|
||||||
});
|
});
|
||||||
|
|
||||||
server.listen(port, '0.0.0.0', function() {
|
server.listen(port, function() {
|
||||||
console.log("ldaps://localhost:%d", port);
|
console.log("ldaps://localhost:%d", port);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user