LDAPv3-0.0.0.0: src/LDAPv3.hs
-- Copyright (c) 2019 Herbert Valerio Riedel <hvr@gnu.org>
--
-- This file is free software: you may copy, redistribute and/or modify it
-- under the terms of the GNU General Public License as published by the
-- Free Software Foundation, either version 2 of the License, or (at your
-- option) any later version.
--
-- This file is distributed in the hope that it will be useful, but
-- WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-- General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program (see `LICENSE`). If not, see
-- <https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>.
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE TypeOperators #-}
-- | This module provides a pure Haskell implementation of the /Lightweight Directory Access Protocol (LDAP)/ version 3 as specified in <https://tools.ietf.org/html/rfc4511 RFC4511>.
--
-- Serializing and deserializing to and from the wire <https://en.wikipedia.org/wiki/ASN.1 ASN.1> encoding is provided via the 'Bin.Binary' instance of 'LDAPMessage'. For the purpose of implementing network clients and servers, the operations
--
-- * 'Bin.encode'
-- * 'Data.Binary.Get.runGetIncremental'
--
-- are most useful.
--
module LDAPv3
( -- * LDAPv3 Protocol data structures
--
-- | The Haskell data structures defined in this module closely follow the protocol specification as laid out in <https://tools.ietf.org/html/rfc4511 RFC4511>.
--
-- For convenience, the normative <https://en.wikipedia.org/wiki/ASN.1 ASN.1> definitions for each Haskell data type are quoted.
-- ** Common Elements (<https://tools.ietf.org/html/rfc4511#section-4.1 RFC4511 Section 4.1>)
-- 4.1.1. Message Envelope
LDAPMessage(..)
, MessageID(..)
, MaxInt
, ProtocolOp(..)
-- 4.1.2. String Types
, LDAPString
, LDAPOID
-- 4.1.3. Distinguished Name and Relative Distinguished Name
, LDAPDN
, RelativeLDAPDN
-- 4.1.4. Attribute Descriptions
, AttributeDescription
-- 4.1.5. Attribute Value
, AttributeValue
-- 4.1.6. Attribute Value Assertion
, AttributeValueAssertion(..)
, AssertionValue
-- 4.1.7. Attribute and PartialAttribute
, PartialAttribute(..)
, Attribute(..)
-- 4.1.8. Matching Rule Identifier
, MatchingRuleId
-- 4.1.9. Result Message
, LDAPResult(..)
, ResultCode(..)
-- 4.1.10. Referral
, Referral
, URI
-- 4.1.11. Controls
, Controls
, Control(..)
-- ** Bind Operation (<https://tools.ietf.org/html/rfc4511#section-4.2 RFC4511 Section 4.2>)
, BindRequest(..)
, AuthenticationChoice(..)
, SaslCredentials(..)
, BindResponse(..)
-- ** Unbind Operation (<https://tools.ietf.org/html/rfc4511#section-4.3 RFC4511 Section 4.3>)
, UnbindRequest
-- ** Unsolicited Notification (<https://tools.ietf.org/html/rfc4511#section-4.4 RFC4511 Section 4.4>)
--
-- | Unsolicited notifications are represented by an 'ExtendedResponse' message with its 'MessageID' set to @0@.
-- ** Search Operation (<https://tools.ietf.org/html/rfc4511#section-4.5 RFC4511 Section 4.5>)
, SearchRequest(..)
, Scope(..)
, DerefAliases(..)
, AttributeSelection
, Filter(..)
, SubstringFilter(..)
, Substring(..)
, MatchingRuleAssertion(..)
-- *** Search Result (<https://tools.ietf.org/html/rfc4511#section-4.5.2 RFC4511 Section 4.5.2>)
, SearchResultEntry(..)
, PartialAttributeList
, SearchResultReference(..)
, SearchResultDone
-- ** Modify Operation (<https://tools.ietf.org/html/rfc4511#section-4.6 RFC4511 Section 4.6>)
, ModifyRequest(..)
, Change(..)
, Operation(..)
, ModifyResponse
-- ** Add Operation (<https://tools.ietf.org/html/rfc4511#section-4.7 RFC4511 Section 4.7>)
, AddRequest(..)
, AttributeList
, AddResponse
-- ** Delete Operation (<https://tools.ietf.org/html/rfc4511#section-4.8 RFC4511 Section 4.8>)
, DelRequest
, DelResponse
-- ** Modify DN Operation (<https://tools.ietf.org/html/rfc4511#section-4.9 RFC4511 Section 4.9>)
, ModifyDNRequest(..)
, ModifyDNResponse
-- ** Compare Operation (<https://tools.ietf.org/html/rfc4511#section-4.10 RFC4511 Section 4.10>)
, CompareRequest(..)
, CompareResponse
-- ** Abandon Operation (<https://tools.ietf.org/html/rfc4511#section-4.11 RFC4511 Section 4.11>)
, AbandonRequest
-- ** Extended Operation (<https://tools.ietf.org/html/rfc4511#section-4.12 RFC4511 Section 4.12>)
, ExtendedRequest(..)
, ExtendedResponse(..)
-- ** Intermediate Response (<https://tools.ietf.org/html/rfc4511#section-4.13 RFC4511 Section 4.13>)
, IntermediateResponse(..)
-- * ASN.1 Helpers
, NULL
, OCTET_STRING
, BOOLEAN_DEFAULT_FALSE(..)
, SET(..)
, SET1(..)
-- ** ASN.1 type-level tagging
, EXPLICIT(..)
, IMPLICIT(..)
, TagK(..)
-- * Unsigned integer sub-type
, UIntBounds
, UInt
, fromUInt
, toUInt
) where
import Common
import Data.ASN1
import Data.ASN1.Prim
import Data.Int.Subtypes
import LDAPv3.ResultCode
import qualified Data.Binary as Bin
----------------------------------------------------------------------------
-- LDAPv3 protocol
{- | Message Envelope (<https://tools.ietf.org/html/rfc4511#section-4.1.1 RFC4511 Section 4.1.1>)
> LDAPMessage ::= SEQUENCE {
> messageID MessageID,
> protocolOp CHOICE {
> bindRequest BindRequest,
> bindResponse BindResponse,
> unbindRequest UnbindRequest,
> searchRequest SearchRequest,
> searchResEntry SearchResultEntry,
> searchResDone SearchResultDone,
> searchResRef SearchResultReference,
> modifyRequest ModifyRequest,
> modifyResponse ModifyResponse,
> addRequest AddRequest,
> addResponse AddResponse,
> delRequest DelRequest,
> delResponse DelResponse,
> modDNRequest ModifyDNRequest,
> modDNResponse ModifyDNResponse,
> compareRequest CompareRequest,
> compareResponse CompareResponse,
> abandonRequest AbandonRequest,
> extendedReq ExtendedRequest,
> extendedResp ExtendedResponse,
> ...,
> intermediateResponse IntermediateResponse },
> controls [0] Controls OPTIONAL }
-}
data LDAPMessage = LDAPMessage
{ _LDAPMessage'messageID :: MessageID
, _LDAPMessage'protocolOp :: ProtocolOp
, _LDAPMessage'controls :: Maybe ('CONTEXTUAL 0 `IMPLICIT` Controls)
} deriving (Generic,Show,Eq)
-- | Encodes to\/from ASN.1 as per <https://tools.ietf.org/html/rfc4511#section-5.1 RFC4511 Section 5.1>
instance Bin.Binary LDAPMessage where
put = void . toBinaryPut . asn1encode
get = toBinaryGet asn1decode
instance ASN1 LDAPMessage where
asn1decodeCompOf = LDAPMessage <$> asn1decode <*> asn1decode <*> asn1decode
asn1encodeCompOf (LDAPMessage v1 v2 v3) = asn1encodeCompOf (v1,v2,v3)
{- | Message ID (<https://tools.ietf.org/html/rfc4511#section-4.1.1.1 RFC4511 Section 4.1.1.1>)
> MessageID ::= INTEGER (0 .. maxInt)
-}
newtype MessageID = MessageID (UInt 0 MaxInt Int32)
deriving (Generic,NFData,Ord,Bounded,ASN1,Show,Eq)
{- | LDAPv3 protocol ASN.1 constant as per <https://tools.ietf.org/html/rfc4511#section-4.1.1 RFC4511 Section 4.1.1>
> maxInt INTEGER ::= 2147483647 -- (2^^31 - 1)
-}
type MaxInt = 2147483647
-- | @CHOICE@ type inlined in @LDAPMessage.protocolOp@ (<https://tools.ietf.org/html/rfc4511#section-4.1.1 RFC4511 Section 4.1.1>)
--
data ProtocolOp
= ProtocolOp'bindRequest BindRequest
| ProtocolOp'bindResponse BindResponse
| ProtocolOp'unbindRequest UnbindRequest
| ProtocolOp'searchRequest SearchRequest
| ProtocolOp'searchResEntry SearchResultEntry
| ProtocolOp'searchResDone SearchResultDone
| ProtocolOp'searchResRef SearchResultReference
| ProtocolOp'modifyRequest ModifyRequest
| ProtocolOp'modifyResponse ModifyResponse
| ProtocolOp'addRequest AddRequest
| ProtocolOp'addResponse AddResponse
| ProtocolOp'delRequest DelRequest
| ProtocolOp'delResponse DelResponse
| ProtocolOp'modDNRequest ModifyDNRequest
| ProtocolOp'modDNResponse ModifyDNResponse
| ProtocolOp'compareRequest CompareRequest
| ProtocolOp'compareResponse CompareResponse
| ProtocolOp'abandonRequest AbandonRequest
| ProtocolOp'extendedReq ExtendedRequest
| ProtocolOp'extendedResp ExtendedResponse
| ProtocolOp'intermediateResponse IntermediateResponse
deriving (Generic,Show,Eq)
instance NFData ProtocolOp
instance ASN1 ProtocolOp where
asn1decode = with'CHOICE
[ ProtocolOp'bindRequest <$> asn1decode
, ProtocolOp'bindResponse <$> asn1decode
, ProtocolOp'unbindRequest <$> asn1decode
, ProtocolOp'searchRequest <$> asn1decode
, ProtocolOp'searchResEntry <$> asn1decode
, ProtocolOp'searchResDone <$> asn1decode
, ProtocolOp'searchResRef <$> asn1decode
, ProtocolOp'modifyRequest <$> asn1decode
, ProtocolOp'modifyResponse <$> asn1decode
, ProtocolOp'addRequest <$> asn1decode
, ProtocolOp'addResponse <$> asn1decode
, ProtocolOp'delRequest <$> asn1decode
, ProtocolOp'delResponse <$> asn1decode
, ProtocolOp'modDNRequest <$> asn1decode
, ProtocolOp'modDNResponse <$> asn1decode
, ProtocolOp'compareRequest <$> asn1decode
, ProtocolOp'compareResponse <$> asn1decode
, ProtocolOp'abandonRequest <$> asn1decode
, ProtocolOp'extendedReq <$> asn1decode
, ProtocolOp'extendedResp <$> asn1decode
, ProtocolOp'intermediateResponse <$> asn1decode
]
asn1encode = \case
ProtocolOp'bindRequest v -> asn1encode v
ProtocolOp'bindResponse v -> asn1encode v
ProtocolOp'unbindRequest v -> asn1encode v
ProtocolOp'searchRequest v -> asn1encode v
ProtocolOp'searchResEntry v -> asn1encode v
ProtocolOp'searchResDone v -> asn1encode v
ProtocolOp'searchResRef v -> asn1encode v
ProtocolOp'modifyRequest v -> asn1encode v
ProtocolOp'modifyResponse v -> asn1encode v
ProtocolOp'addRequest v -> asn1encode v
ProtocolOp'addResponse v -> asn1encode v
ProtocolOp'delRequest v -> asn1encode v
ProtocolOp'delResponse v -> asn1encode v
ProtocolOp'modDNRequest v -> asn1encode v
ProtocolOp'modDNResponse v -> asn1encode v
ProtocolOp'compareRequest v -> asn1encode v
ProtocolOp'compareResponse v -> asn1encode v
ProtocolOp'abandonRequest v -> asn1encode v
ProtocolOp'extendedReq v -> asn1encode v
ProtocolOp'extendedResp v -> asn1encode v
ProtocolOp'intermediateResponse v -> asn1encode v
----------------------------------------------------------------------------
{- | Controls (<https://tools.ietf.org/html/rfc4511#section-4.1.11 RFC4511 Section 4.1.11>)
> Controls ::= SEQUENCE OF control Control
-}
type Controls = [Control]
{- | Control Entry (<https://tools.ietf.org/html/rfc4511#section-4.1.11 RFC4511 Section 4.1.11>)
> Control ::= SEQUENCE {
> controlType LDAPOID,
> criticality BOOLEAN DEFAULT FALSE,
> controlValue OCTET STRING OPTIONAL }
-}
data Control = Control
{ _Control'controlType :: LDAPOID
, _Control'criticality :: Maybe BOOLEAN_DEFAULT_FALSE
, _Control'controlValue :: Maybe OCTET_STRING
} deriving (Generic,Show,Eq)
instance NFData Control
instance ASN1 Control where
asn1decodeCompOf = Control <$> asn1decode <*> asn1decode <*> asn1decode
asn1encodeCompOf (Control v1 v2 v3) = asn1encodeCompOf (v1,v2,v3)
{- | Object identifier (<https://tools.ietf.org/html/rfc4511#section-4.1.2 RFC4511 Section 4.1.2>)
> LDAPOID ::= OCTET STRING -- Constrained to <numericoid>
> -- [RFC4512]
-}
type LDAPOID = OCTET_STRING
----------------------------------------------------------------------------
{- | Bind Request (<https://tools.ietf.org/html/rfc4511#section-4.2 RFC4511 Section 4.2>)
> BindRequest ::= [APPLICATION 0] SEQUENCE {
> version INTEGER (1 .. 127),
> name LDAPDN,
> authentication AuthenticationChoice }
-}
data BindRequest = BindRequest
{ bindRequest'version :: UInt 1 127 Int8
, bindRequest'name :: LDAPDN
, bindRequest'authentication :: AuthenticationChoice
} deriving (Generic,Show,Eq)
instance NFData BindRequest
instance ASN1 BindRequest where
asn1defTag _ = Application 0
asn1decodeCompOf = BindRequest <$> asn1decode <*> asn1decode <*> asn1decode
asn1encodeCompOf (BindRequest v1 v2 v3) = asn1encodeCompOf (v1,v2,v3)
----------------------------------------------------------------------------
{- | See 'BindRequest'
> AuthenticationChoice ::= CHOICE {
> simple [0] OCTET STRING,
> -- 1 and 2 reserved
> sasl [3] SaslCredentials,
> ... }
-}
data AuthenticationChoice
= AuthenticationChoice'simple ('CONTEXTUAL 0 `IMPLICIT` OCTET_STRING)
| AuthenticationChoice'sasl ('CONTEXTUAL 3 `IMPLICIT` SaslCredentials)
deriving (Generic,Show,Eq)
instance NFData AuthenticationChoice
instance ASN1 AuthenticationChoice where
asn1decode = with'CHOICE
[ AuthenticationChoice'simple <$> asn1decode
, AuthenticationChoice'sasl <$> asn1decode
]
asn1encode = \case
AuthenticationChoice'simple v -> asn1encode v
AuthenticationChoice'sasl v -> asn1encode v
{- | See 'AuthenticationChoice'
> SaslCredentials ::= SEQUENCE {
> mechanism LDAPString,
> credentials OCTET STRING OPTIONAL }
-}
data SaslCredentials = SaslCredentials
{ _SaslCredentials'mechanism :: LDAPString
, _SaslCredentials'credentials :: Maybe OCTET_STRING
} deriving (Generic,Show,Eq)
instance NFData SaslCredentials
instance ASN1 SaslCredentials where
asn1decodeCompOf = SaslCredentials <$> asn1decode <*> asn1decode
asn1encodeCompOf (SaslCredentials v1 v2) = asn1encodeCompOf (v1,v2)
----------------------------------------------------------------------------
{- | Bind Response (<https://tools.ietf.org/html/rfc4511#section-4.2 RFC4511 Section 4.2>)
> BindResponse ::= [APPLICATION 1] SEQUENCE {
> COMPONENTS OF LDAPResult,
> serverSaslCreds [7] OCTET STRING OPTIONAL }
-}
data BindResponse = BindResponse
{ _BindResponse'LDAPResult :: LDAPResult
, _BindResponse'serverSaslCreds :: Maybe ('CONTEXTUAL 7 `IMPLICIT` OCTET_STRING)
} deriving (Generic,Show,Eq)
instance NFData BindResponse
instance ASN1 BindResponse where
asn1defTag _ = Application 1
asn1decodeCompOf = do
_BindResponse'LDAPResult <- asn1decodeCompOf
_BindResponse'serverSaslCreds <- asn1decode
pure BindResponse{..}
asn1encodeCompOf (BindResponse{..})
= enc'SEQUENCE_COMPS [ asn1encodeCompOf _BindResponse'LDAPResult
, asn1encode _BindResponse'serverSaslCreds
]
----------------------------------------------------------------------------
{- | Unbind Operation (<https://tools.ietf.org/html/rfc4511#section-4.3 RFC4511 Section 4.3>)
> UnbindRequest ::= [APPLICATION 2] NULL
-}
type UnbindRequest = ('APPLICATION 2 `IMPLICIT` NULL)
----------------------------------------------------------------------------
{- | Search Request (<https://tools.ietf.org/html/rfc4511#section-4.5.1 RFC4511 Section 4.5.1>)
> SearchRequest ::= [APPLICATION 3] SEQUENCE {
> baseObject LDAPDN,
> scope ENUMERATED {
> baseObject (0),
> singleLevel (1),
> wholeSubtree (2),
> ... },
> derefAliases ENUMERATED {
> neverDerefAliases (0),
> derefInSearching (1),
> derefFindingBaseObj (2),
> derefAlways (3) },
> sizeLimit INTEGER (0 .. maxInt),
> timeLimit INTEGER (0 .. maxInt),
> typesOnly BOOLEAN,
> filter Filter,
> attributes AttributeSelection }
-}
data SearchRequest = SearchRequest
{ _SearchRequest'baseObject :: LDAPDN
, _SearchRequest'scope :: Scope
, _SearchRequest'derefAliases :: DerefAliases
, _SearchRequest'sizeLimit :: (UInt 0 MaxInt Int32)
, _SearchRequest'timeLimit :: (UInt 0 MaxInt Int32)
, _SearchRequest'typesOnly :: Bool
, _SearchRequest'filter :: Filter
, _SearchRequest'attributes :: AttributeSelection
} deriving (Generic,Show,Eq)
instance NFData SearchRequest
{- | See 'SearchRequest'
> AttributeSelection ::= SEQUENCE OF selector LDAPString
> -- The LDAPString is constrained to
> -- <attributeSelector> in Section 4.5.1.8
-}
type AttributeSelection = [LDAPString]
instance ASN1 SearchRequest where
asn1decode = implicit (Application 3) $ with'SEQUENCE $ do
_SearchRequest'baseObject <- asn1decode
_SearchRequest'scope <- asn1decode
_SearchRequest'derefAliases <- asn1decode
_SearchRequest'sizeLimit <- asn1decode
_SearchRequest'timeLimit <- asn1decode
_SearchRequest'typesOnly <- asn1decode
_SearchRequest'filter <- asn1decode
_SearchRequest'attributes <- asn1decode
pure SearchRequest{..}
asn1encode (SearchRequest v1 v2 v3 v4 v5 v6 v7 v8)
= retag (Application 3) $
enc'SEQUENCE [ asn1encode v1
, asn1encode v2
, asn1encode v3
, asn1encode v4
, asn1encode v5
, asn1encode v6
, asn1encode v7
, asn1encode v8
]
-- | See 'SearchRequest' (<https://tools.ietf.org/html/rfc4511#section-4.5.1.2 RFC4511 Section 4.5.1.2>)
data Scope
= Scope'baseObject
| Scope'singleLevel
| Scope'wholeSubtree
deriving (Generic,Bounded,Enum,Show,Eq)
instance NFData Scope where
rnf = rwhnf
instance ASN1 Scope where
asn1decode = dec'BoundedEnum
asn1encode = enc'BoundedEnum
-- | See 'SearchRequest' (<https://tools.ietf.org/html/rfc4511#section-4.5.1.3 RFC4511 Section 4.5.1.3>)
data DerefAliases
= DerefAliases'neverDerefAliases
| DerefAliases'derefInSearching
| DerefAliases'derefFindingBaseObj
| DerefAliases'derefAlways
deriving (Generic,Bounded,Enum,Show,Eq)
instance NFData DerefAliases where
rnf = rwhnf
instance ASN1 DerefAliases where
asn1decode = dec'BoundedEnum
asn1encode = enc'BoundedEnum
{- | Search Filter (<https://tools.ietf.org/html/rfc4511#section-4.5.1.7 RFC4511 Section 4.5.1.7>)
> Filter ::= CHOICE {
> and [0] SET SIZE (1..MAX) OF filter Filter,
> or [1] SET SIZE (1..MAX) OF filter Filter,
> not [2] Filter,
> equalityMatch [3] AttributeValueAssertion,
> substrings [4] SubstringFilter,
> greaterOrEqual [5] AttributeValueAssertion,
> lessOrEqual [6] AttributeValueAssertion,
> present [7] AttributeDescription,
> approxMatch [8] AttributeValueAssertion,
> extensibleMatch [9] MatchingRuleAssertion,
> ... }
-}
data Filter
= Filter'and ('CONTEXTUAL 0 `IMPLICIT` SET1 Filter)
| Filter'or ('CONTEXTUAL 1 `IMPLICIT` SET1 Filter)
| Filter'not ('CONTEXTUAL 2 `EXPLICIT` Filter)
| Filter'equalityMatch ('CONTEXTUAL 3 `IMPLICIT` AttributeValueAssertion)
| Filter'substrings ('CONTEXTUAL 4 `IMPLICIT` SubstringFilter)
| Filter'greaterOrEqual ('CONTEXTUAL 5 `IMPLICIT` AttributeValueAssertion)
| Filter'lessOrEqual ('CONTEXTUAL 6 `IMPLICIT` AttributeValueAssertion)
| Filter'present ('CONTEXTUAL 7 `IMPLICIT` AttributeDescription)
| Filter'approxMatch ('CONTEXTUAL 8 `IMPLICIT` AttributeValueAssertion)
| Filter'extensibleMatch ('CONTEXTUAL 9 `IMPLICIT` MatchingRuleAssertion)
deriving (Generic,Show,Eq)
instance NFData Filter
instance ASN1 Filter where
asn1decode = with'CHOICE
[ Filter'and <$> asn1decode
, Filter'or <$> asn1decode
, Filter'not <$> asn1decode
, Filter'equalityMatch <$> asn1decode
, Filter'substrings <$> asn1decode
, Filter'greaterOrEqual <$> asn1decode
, Filter'lessOrEqual <$> asn1decode
, Filter'present <$> asn1decode
, Filter'approxMatch <$> asn1decode
, Filter'extensibleMatch <$> asn1decode
]
asn1encode = \case
Filter'and v -> asn1encode v
Filter'or v -> asn1encode v
Filter'not v -> asn1encode v
Filter'equalityMatch v -> asn1encode v
Filter'substrings v -> asn1encode v
Filter'greaterOrEqual v -> asn1encode v
Filter'lessOrEqual v -> asn1encode v
Filter'present v -> asn1encode v
Filter'approxMatch v -> asn1encode v
Filter'extensibleMatch v -> asn1encode v
{- | Attribute Descriptions (<https://tools.ietf.org/html/rfc4511#section-4.1.4 RFC4511 Section 4.1.4>)
> AttributeDescription ::= LDAPString
> -- Constrained to <attributedescription>
> -- [RFC4512]
-}
type AttributeDescription = LDAPString
{- | Attribute Value (<https://tools.ietf.org/html/rfc4511#section-4.1.5 RFC4511 Section 4.1.5>)
> AttributeValue ::= OCTET STRING
-}
type AttributeValue = OCTET_STRING
{- | Attribute Value Assertion (<https://tools.ietf.org/html/rfc4511#section-4.1.6 RFC4511 Section 4.1.6>)
> AttributeValueAssertion ::= SEQUENCE {
> attributeDesc AttributeDescription,
> assertionValue AssertionValue }
-}
data AttributeValueAssertion = AttributeValueAssertion
{ _AttributeValueAssertion'attributeDesc :: AttributeDescription
, _AttributeValueAssertion'assertionValue :: AssertionValue
} deriving (Generic,Show,Eq)
instance NFData AttributeValueAssertion
-- | > AssertionValue ::= OCTET STRING
type AssertionValue = OCTET_STRING
instance ASN1 AttributeValueAssertion where
asn1decodeCompOf = AttributeValueAssertion <$> asn1decode <*> asn1decode
asn1encodeCompOf (AttributeValueAssertion v1 v2) = asn1encodeCompOf (v1,v2)
{- | Substring 'Filter' (<https://tools.ietf.org/html/rfc4511#section-4.5.1.7.2 RFC4511 Section 4.5.1.7.2>)
> SubstringFilter ::= SEQUENCE {
> type AttributeDescription,
> substrings SEQUENCE SIZE (1..MAX) OF substring CHOICE {
> initial [0] AssertionValue, -- can occur at most once
> any [1] AssertionValue,
> final [2] AssertionValue } -- can occur at most once
> }
__NOTE__: The additional invariants imposed on the ordering and occurence counts of the @initial@ and @final@ entries MUST currently be enforced by the consumer of this library. Future versions of this library might change to enforce these invariants at the type-level.
Specifically, the invariant stated by the specification is:
/There SHALL be at most one @initial@ and at most one @final@ in the @substrings@ of a SubstringFilter. If @initial@ is present, it SHALL be the first element of @substrings@. If @final@ is present, it SHALL be the last element of @substrings@./
-}
data SubstringFilter = SubstringFilter
{ _SubstringFilter'type :: AttributeDescription
, _SubstringFilter'substrings :: NonEmpty Substring
} deriving (Generic,Show,Eq)
instance NFData SubstringFilter
instance ASN1 SubstringFilter where
asn1decodeCompOf = SubstringFilter <$> asn1decode <*> asn1decode
asn1encodeCompOf (SubstringFilter v1 v2) = asn1encodeCompOf (v1,v2)
-- | See 'SubstringFilter'
data Substring
= Substring'initial ('CONTEXTUAL 0 `IMPLICIT` AssertionValue) -- ^ may occur at most once; must be first element if present
| Substring'any ('CONTEXTUAL 1 `IMPLICIT` AssertionValue)
| Substring'final ('CONTEXTUAL 2 `IMPLICIT` AssertionValue) -- ^ may occur at most once; must be last element if present
deriving (Generic,Show,Eq)
instance NFData Substring
instance ASN1 Substring where
asn1decode = with'CHOICE
[ Substring'initial <$> asn1decode
, Substring'any <$> asn1decode
, Substring'final <$> asn1decode
]
asn1encode = \case
Substring'initial v -> asn1encode v
Substring'any v -> asn1encode v
Substring'final v -> asn1encode v
{- | Matching Rule Identifier (<https://tools.ietf.org/html/rfc4511#section-4.1.8 RFC4511 Section 4.1.8>)
> MatchingRuleId ::= LDAPString
-}
type MatchingRuleId = LDAPString
{- | See 'SearchRequest' 'Filter'
> MatchingRuleAssertion ::= SEQUENCE {
> matchingRule [1] MatchingRuleId OPTIONAL,
> type [2] AttributeDescription OPTIONAL,
> matchValue [3] AssertionValue,
> dnAttributes [4] BOOLEAN DEFAULT FALSE }
-}
data MatchingRuleAssertion = MatchingRuleAssertion
{ _MatchingRuleAssertion'matchingRule :: Maybe ('CONTEXTUAL 1 `IMPLICIT` MatchingRuleId)
, _MatchingRuleAssertion'type :: Maybe ('CONTEXTUAL 2 `IMPLICIT` AttributeDescription)
, _MatchingRuleAssertion'matchValue :: ('CONTEXTUAL 3 `IMPLICIT` AssertionValue)
, _MatchingRuleAssertion'dnAttributes :: Maybe ('CONTEXTUAL 4 `IMPLICIT` BOOLEAN_DEFAULT_FALSE)
} deriving (Generic,Show,Eq)
instance NFData MatchingRuleAssertion
instance ASN1 MatchingRuleAssertion where
asn1decodeCompOf = MatchingRuleAssertion <$> asn1decode <*> asn1decode <*> asn1decode <*> asn1decode
asn1encodeCompOf (MatchingRuleAssertion v1 v2 v3 v4) = asn1encodeCompOf (v1,v2,v3,v4)
----------------------------------------------------------------------------
{- | Search Result Continuation Reference (<https://tools.ietf.org/html/rfc4511#section-4.5.3 RFC4511 Section 4.5.3>)
> SearchResultReference ::= [APPLICATION 19] SEQUENCE
> SIZE (1..MAX) OF uri URI
-}
newtype SearchResultReference = SearchResultReference (NonEmpty URI)
deriving (Generic,NFData,Show,Eq)
instance ASN1 SearchResultReference where
asn1defTag _ = Application 19 -- not used
asn1decode = SearchResultReference <$> (Application 19 `implicit` asn1decode)
asn1encode (SearchResultReference v) = retag (Application 19) $ asn1encode v
----------------------------------------------------------------------------
{- | Search Result Entry (<https://tools.ietf.org/html/rfc4511#section-4.5.2 RFC4511 Section 4.5.2>)
> SearchResultEntry ::= [APPLICATION 4] SEQUENCE {
> objectName LDAPDN,
> attributes PartialAttributeList }
-}
data SearchResultEntry = SearchResultEntry
{ _SearchResultEntry'objectName :: LDAPDN
, _SearchResultEntry'attributes :: PartialAttributeList
} deriving (Generic,Show,Eq)
instance NFData SearchResultEntry
instance ASN1 SearchResultEntry where
asn1defTag _ = Application 4
asn1decodeCompOf = SearchResultEntry <$> asn1decode <*> asn1decode
asn1encodeCompOf (SearchResultEntry v1 v2) = asn1encodeCompOf (v1,v2)
{- | See 'SearchResultEntry'
> PartialAttributeList ::= SEQUENCE OF
> partialAttribute PartialAttribute
-}
type PartialAttributeList = [PartialAttribute]
{- | Partial Attribute (<https://tools.ietf.org/html/rfc4511#section-4.1.7 RFC4511 Section 4.1.7>)
> PartialAttribute ::= SEQUENCE {
> type AttributeDescription,
> vals SET OF value AttributeValue }
-}
data PartialAttribute = PartialAttribute
{ _PartialAttribute'type :: AttributeDescription
, _PartialAttribute'vals :: SET AttributeValue
} deriving (Generic,Show,Eq)
instance NFData PartialAttribute
instance ASN1 PartialAttribute where
asn1decodeCompOf = PartialAttribute <$> asn1decode <*> asn1decode
asn1encodeCompOf (PartialAttribute v1 v2) = asn1encodeCompOf (v1,v2)
{- | Attribute (<https://tools.ietf.org/html/rfc4511#section-4.1.7 RFC4511 Section 4.1.7>)
> Attribute ::= PartialAttribute(WITH COMPONENTS {
> ...,
> vals (SIZE(1..MAX))})
-}
data Attribute = Attribute
{ _Attribute'type :: AttributeDescription
, _Attribute'vals :: SET1 AttributeValue
} deriving (Generic,Show,Eq)
instance NFData Attribute
instance ASN1 Attribute where
asn1decodeCompOf = Attribute <$> asn1decode <*> asn1decode
asn1encodeCompOf (Attribute v1 v2) = asn1encodeCompOf (v1,v2)
----------------------------------------------------------------------------
{- | Search Result Done (<https://tools.ietf.org/html/rfc4511#section-4.5.2 RFC4511 Section 4.5.2>)
> SearchResultDone ::= [APPLICATION 5] LDAPResult
-}
type SearchResultDone = ('APPLICATION 5 `IMPLICIT` LDAPResult)
----------------------------------------------------------------------------
{- | Result Message (<https://tools.ietf.org/html/rfc4511#section-4.1.9 RFC4511 Section 4.1.9>)
> LDAPResult ::= SEQUENCE {
> resultCode ENUMERATED {
> success (0),
> operationsError (1),
> protocolError (2),
> timeLimitExceeded (3),
> sizeLimitExceeded (4),
> compareFalse (5),
> compareTrue (6),
> authMethodNotSupported (7),
> strongerAuthRequired (8),
> -- 9 reserved --
> referral (10),
> adminLimitExceeded (11),
> unavailableCriticalExtension (12),
> confidentialityRequired (13),
> saslBindInProgress (14),
> noSuchAttribute (16),
> undefinedAttributeType (17),
> inappropriateMatching (18),
> constraintViolation (19),
> attributeOrValueExists (20),
> invalidAttributeSyntax (21),
> -- 22-31 unused --
> noSuchObject (32),
> aliasProblem (33),
> invalidDNSyntax (34),
> -- 35 reserved for undefined isLeaf --
> aliasDereferencingProblem (36),
> -- 37-47 unused --
> inappropriateAuthentication (48),
> invalidCredentials (49),
> insufficientAccessRights (50),
> busy (51),
> unavailable (52),
> unwillingToPerform (53),
> loopDetect (54),
> -- 55-63 unused --
> namingViolation (64),
> objectClassViolation (65),
> notAllowedOnNonLeaf (66),
> notAllowedOnRDN (67),
> entryAlreadyExists (68),
> objectClassModsProhibited (69),
> -- 70 reserved for CLDAP --
> affectsMultipleDSAs (71),
> -- 72-79 unused --
> other (80),
> ... },
> matchedDN LDAPDN,
> diagnosticMessage LDAPString,
> referral [3] Referral OPTIONAL }
-}
data LDAPResult = LDAPResult
{ _LDAPResult'resultCode :: ResultCode
, _LDAPResult'matchedDN :: LDAPDN
, _LDAPResult'diagnosticMessage :: LDAPString
, _LDAPResult'referral :: Maybe ('CONTEXTUAL 3 `IMPLICIT` Referral)
} deriving (Generic,Show,Eq)
instance NFData LDAPResult
{- | Referral result code (<https://tools.ietf.org/html/rfc4511#section-4.1.10 RFC4511 Section 4.1.10>)
> Referral ::= SEQUENCE SIZE (1..MAX) OF uri URI
-}
type Referral = ('CONTEXTUAL 3 `IMPLICIT` NonEmpty URI)
{- |
> URI ::= LDAPString -- limited to characters permitted in
> -- URIs
-}
type URI = LDAPString
instance ASN1 LDAPResult where
asn1decodeCompOf = do
_LDAPResult'resultCode <- asn1decode
_LDAPResult'matchedDN <- asn1decode
_LDAPResult'diagnosticMessage <- asn1decode
_LDAPResult'referral <- asn1decode
pure LDAPResult{..}
asn1encodeCompOf (LDAPResult v1 v2 v3 v4) = asn1encodeCompOf (v1,v2,v3,v4)
{- | String Type (<https://tools.ietf.org/html/rfc4511#section-4.1.2 RFC4511 Section 4.1.2>)
> LDAPString ::= OCTET STRING -- UTF-8 encoded,
> -- [ISO10646] characters
-}
type LDAPString = ShortText
{- | Distinguished Name (<https://tools.ietf.org/html/rfc4511#section-4.1.3 RFC4511 Section 4.1.3>)
> LDAPDN ::= LDAPString -- Constrained to <distinguishedName>
> -- [RFC4514]
-}
type LDAPDN = LDAPString
{- | Relative Distinguished Name (<https://tools.ietf.org/html/rfc4511#section-4.1.3 RFC4511 Section 4.1.3>)
> RelativeLDAPDN ::= LDAPString -- Constrained to <name-component>
> -- [RFC4514]
-}
type RelativeLDAPDN = LDAPString
{- | Modify Operation (<https://tools.ietf.org/html/rfc4511#section-4.6 RFC4511 Section 4.6>)
> ModifyRequest ::= [APPLICATION 6] SEQUENCE {
> object LDAPDN,
> changes SEQUENCE OF change SEQUENCE {
> operation ENUMERATED {
> add (0),
> delete (1),
> replace (2),
> ... },
> modification PartialAttribute } }
-}
data ModifyRequest = ModifyRequest
{ _ModifyRequest'object :: LDAPDN
, _ModifyRequest'changes :: [Change]
} deriving (Generic,Show,Eq)
instance NFData ModifyRequest
instance ASN1 ModifyRequest where
asn1defTag _ = Application 6
asn1decodeCompOf = ModifyRequest <$> asn1decode <*> asn1decode
asn1encodeCompOf (ModifyRequest v1 v2) = asn1encodeCompOf (v1,v2)
-- | See 'ModifyRequest'
data Change = Change
{ _Change'operation :: Operation
, _Change'modification :: PartialAttribute
} deriving (Generic,Show,Eq)
instance NFData Change
instance ASN1 Change where
asn1decodeCompOf = Change <$> asn1decode <*> asn1decode
asn1encodeCompOf (Change v1 v2) = asn1encodeCompOf (v1,v2)
-- | See 'ModifyRequest' and 'Change'
data Operation
= Operation'add
| Operation'delete
| Operation'replace
deriving (Generic,Bounded,Enum,Show,Eq)
instance NFData Operation where
rnf = rwhnf
instance ASN1 Operation where
asn1decode = dec'BoundedEnum
asn1encode = enc'BoundedEnum
{- | Modify Response (<https://tools.ietf.org/html/rfc4511#section-4.6 RFC4511 Section 4.6>)
> ModifyResponse ::= [APPLICATION 7] LDAPResult
-}
type ModifyResponse = ('APPLICATION 7 `IMPLICIT` LDAPResult)
{- | Add Operation (<https://tools.ietf.org/html/rfc4511#section-4.7 RFC4511 Section 4.7>)
> AddRequest ::= [APPLICATION 8] SEQUENCE {
> entry LDAPDN,
> attributes AttributeList }
-}
data AddRequest = AddRequest
{ _AddRequest'entry :: LDAPDN
, _AddRequest'attributes :: AttributeList
} deriving (Generic,Show,Eq)
instance NFData AddRequest
instance ASN1 AddRequest where
asn1defTag _ = Application 8
asn1decodeCompOf = AddRequest <$> asn1decode <*> asn1decode
asn1encodeCompOf (AddRequest v1 v2) = asn1encodeCompOf (v1,v2)
{- | Attribute List
> AttributeList ::= SEQUENCE OF attribute Attribute
-}
type AttributeList = [Attribute]
{- | Add Response (<https://tools.ietf.org/html/rfc4511#section-4.7 RFC4511 Section 4.7>)
> AddResponse ::= [APPLICATION 9] LDAPResult
-}
type AddResponse = ('APPLICATION 9 `IMPLICIT` LDAPResult)
{- | Delete Operation (<https://tools.ietf.org/html/rfc4511#section-4.8 RFC4511 Section 4.8>)
> DelRequest ::= [APPLICATION 10] LDAPDN
-}
type DelRequest = ('APPLICATION 10 `IMPLICIT` LDAPDN)
{- | Delete Response (<https://tools.ietf.org/html/rfc4511#section-4.8 RFC4511 Section 4.8>)
> DelResponse ::= [APPLICATION 11] LDAPResult
-}
type DelResponse = ('APPLICATION 11 `IMPLICIT` LDAPResult)
{- | Modify DN Operation (<https://tools.ietf.org/html/rfc4511#section-4.9 RFC4511 Section 4.9>)
ModifyDNRequest ::= [APPLICATION 12] SEQUENCE {
entry LDAPDN,
newrdn RelativeLDAPDN,
deleteoldrdn BOOLEAN,
newSuperior [0] LDAPDN OPTIONAL }
-}
data ModifyDNRequest = ModifyDNRequest
{ _ModifyDNRequest'entry :: LDAPDN
, _ModifyDNRequest'newrdn :: RelativeLDAPDN
, _ModifyDNRequest'deleteoldrdn :: Bool
, _ModifyDNRequest'newSuperior :: Maybe ('CONTEXTUAL 0 `IMPLICIT` LDAPDN)
} deriving (Generic,Show,Eq)
instance NFData ModifyDNRequest
instance ASN1 ModifyDNRequest where
asn1defTag _ = Application 12
asn1decodeCompOf = ModifyDNRequest <$> asn1decode <*> asn1decode <*> asn1decode <*> asn1decode
asn1encodeCompOf (ModifyDNRequest v1 v2 v3 v4) = asn1encodeCompOf (v1,v2,v3,v4)
{- | Modify DN Response (<https://tools.ietf.org/html/rfc4511#section-4.9 RFC4511 Section 4.9>)
> ModifyDNResponse ::= [APPLICATION 13] LDAPResult
-}
type ModifyDNResponse = ('APPLICATION 13 `IMPLICIT` LDAPResult)
{- | Compare Operation (<https://tools.ietf.org/html/rfc4511#section-4.10 RFC4511 Section 4.10>)
> CompareRequest ::= [APPLICATION 14] SEQUENCE {
> entry LDAPDN,
> ava AttributeValueAssertion }
-}
data CompareRequest = CompareRequest
{ _CompareRequest'entry :: LDAPDN
, _CompareRequest'ava :: AttributeValueAssertion
} deriving (Generic,Show,Eq)
instance NFData CompareRequest
instance ASN1 CompareRequest where
asn1defTag _ = Application 14
asn1decodeCompOf = CompareRequest <$> asn1decode <*> asn1decode
asn1encodeCompOf (CompareRequest v1 v2) = asn1encodeCompOf (v1,v2)
{- | Compare Response (<https://tools.ietf.org/html/rfc4511#section-4.10 RFC4511 Section 4.10>)
> CompareResponse ::= [APPLICATION 15] LDAPResult
-}
type CompareResponse = ('APPLICATION 15 `IMPLICIT` LDAPResult)
{- | Abandon Operation (<https://tools.ietf.org/html/rfc4511#section-4.11 RFC4511 Section 4.11>)
> AbandonRequest ::= [APPLICATION 16] MessageID
-}
type AbandonRequest = ('APPLICATION 16 `IMPLICIT` MessageID)
{- | Extended Request (<https://tools.ietf.org/html/rfc4511#section-4.12 RFC4511 Section 4.12>)
> ExtendedRequest ::= [APPLICATION 23] SEQUENCE {
> requestName [0] LDAPOID,
> requestValue [1] OCTET STRING OPTIONAL }
-}
data ExtendedRequest = ExtendedRequest
{ _ExtendedRequest'responseName :: ('CONTEXTUAL 0 `IMPLICIT` LDAPOID)
, _ExtendedRequest'responseValue :: Maybe ('CONTEXTUAL 1 `IMPLICIT` OCTET_STRING)
} deriving (Generic,Show,Eq)
instance NFData ExtendedRequest
instance ASN1 ExtendedRequest where
asn1defTag _ = Application 23
asn1decodeCompOf = ExtendedRequest <$> asn1decode <*> asn1decode
asn1encodeCompOf (ExtendedRequest v1 v2) = asn1encodeCompOf (v1,v2)
{- | Extended Response (<https://tools.ietf.org/html/rfc4511#section-4.12 RFC4511 Section 4.12>)
> ExtendedResponse ::= [APPLICATION 24] SEQUENCE {
> COMPONENTS OF LDAPResult,
> responseName [10] LDAPOID OPTIONAL,
> responseValue [11] OCTET STRING OPTIONAL }
-}
data ExtendedResponse = ExtendedResponse
{ _ExtendedResponse'LDAPResult :: LDAPResult
, _ExtendedResponse'responseName :: Maybe ('CONTEXTUAL 10 `IMPLICIT` LDAPOID)
, _ExtendedResponse'responseValue :: Maybe ('CONTEXTUAL 11 `IMPLICIT` OCTET_STRING)
} deriving (Generic,Show,Eq)
instance NFData ExtendedResponse
instance ASN1 ExtendedResponse where
asn1defTag _ = Application 24
asn1decodeCompOf = do
_ExtendedResponse'LDAPResult <- asn1decodeCompOf
_ExtendedResponse'responseName <- asn1decode
_ExtendedResponse'responseValue <- asn1decode
pure ExtendedResponse{..}
asn1encodeCompOf (ExtendedResponse{..})
= enc'SEQUENCE_COMPS [ asn1encodeCompOf _ExtendedResponse'LDAPResult
, asn1encode _ExtendedResponse'responseName
, asn1encode _ExtendedResponse'responseValue
]
{- | Intermediate Response (<https://tools.ietf.org/html/rfc4511#section-4.13 RFC4511 Section 4.13>)
> IntermediateResponse ::= [APPLICATION 25] SEQUENCE {
> responseName [0] LDAPOID OPTIONAL,
> responseValue [1] OCTET STRING OPTIONAL }
-}
data IntermediateResponse = IntermediateResponse
{ _IntermediateResponse'responseName :: Maybe ('CONTEXTUAL 0 `IMPLICIT` LDAPOID)
, _IntermediateResponse'responseValue :: Maybe ('CONTEXTUAL 1 `IMPLICIT` OCTET_STRING)
} deriving (Generic,Show,Eq)
instance NFData IntermediateResponse
instance ASN1 IntermediateResponse where
asn1defTag _ = Application 25
asn1decodeCompOf = IntermediateResponse <$> asn1decode <*> asn1decode
asn1encodeCompOf (IntermediateResponse v1 v2) = asn1encodeCompOf (v1,v2)