1<?php
2
3/**
4 * This file is part of the FreeDSx LDAP package.
5 *
6 * (c) Chad Sikorra <Chad.Sikorra@gmail.com>
7 *
8 * For the full copyright and license information, please view the LICENSE
9 * file that was distributed with this source code.
10 */
11
12namespace FreeDSx\Ldap;
13
14use FreeDSx\Asn1\Type\AbstractType;
15use FreeDSx\Ldap\Entry\Attribute;
16use FreeDSx\Ldap\Entry\Change;
17use FreeDSx\Ldap\Entry\Dn;
18use FreeDSx\Ldap\Entry\Entry;
19use FreeDSx\Ldap\Entry\Rdn;
20use FreeDSx\Ldap\Exception\UnexpectedValueException;
21use FreeDSx\Ldap\Operation\Request\AbandonRequest;
22use FreeDSx\Ldap\Operation\Request\AddRequest;
23use FreeDSx\Ldap\Operation\Request\AnonBindRequest;
24use FreeDSx\Ldap\Operation\Request\CancelRequest;
25use FreeDSx\Ldap\Operation\Request\CompareRequest;
26use FreeDSx\Ldap\Operation\Request\DeleteRequest;
27use FreeDSx\Ldap\Operation\Request\ExtendedRequest;
28use FreeDSx\Ldap\Operation\Request\ModifyDnRequest;
29use FreeDSx\Ldap\Operation\Request\ModifyRequest;
30use FreeDSx\Ldap\Operation\Request\PasswordModifyRequest;
31use FreeDSx\Ldap\Operation\Request\SaslBindRequest;
32use FreeDSx\Ldap\Operation\Request\SearchRequest;
33use FreeDSx\Ldap\Operation\Request\SimpleBindRequest;
34use FreeDSx\Ldap\Operation\Request\UnbindRequest;
35use FreeDSx\Ldap\Protocol\ProtocolElementInterface;
36use FreeDSx\Ldap\Search\Filter\FilterInterface;
37use FreeDSx\Ldap\Search\Filters;
38
39/**
40 * Provides a set of factory methods to help quickly construct different operations/requests.
41 *
42 * @author Chad Sikorra <Chad.Sikorra@gmail.com>
43 */
44class Operations
45{
46    /**
47     * A request to abandon an ongoing operation.
48     *
49     * @param int $id
50     * @return AbandonRequest
51     */
52    public static function abandon(int $id)
53    {
54        return new AbandonRequest($id);
55    }
56
57    /**
58     * Add an entry to LDAP.
59     *
60     * @param Entry $entry
61     * @return AddRequest
62     */
63    public static function add(Entry $entry)
64    {
65        return new AddRequest($entry);
66    }
67
68    /**
69     * A simple bind request with a username and password.
70     *
71     * @param string $username
72     * @param string $password
73     * @return SimpleBindRequest
74     */
75    public static function bind(string $username, string $password)
76    {
77        return new SimpleBindRequest($username, $password);
78    }
79
80    /**
81     * A SASL bind request with a specific mechanism and their associated options.
82     *
83     * @param array $options
84     * @param string $mechanism
85     * @param string|null $credentials
86     * @return SaslBindRequest
87     */
88    public static function bindSasl(array $options = [], string $mechanism = '', ?string $credentials = null)
89    {
90        return new SaslBindRequest($mechanism, $credentials, $options);
91    }
92
93    /**
94     * An anonymous bind request.
95     *
96     * @param string $username
97     * @return AnonBindRequest
98     */
99    public static function bindAnonymously(string $username = '')
100    {
101        return new AnonBindRequest($username);
102    }
103
104    /**
105     * Cancel a specific operation. Pass either the message ID or the LdapMessage object.
106     */
107    public static function cancel(int $messageId): CancelRequest
108    {
109        return new CancelRequest($messageId);
110    }
111
112    /**
113     * A comparison operation to check if an entry has an attribute with a certain value.
114     *
115     * @return CompareRequest
116     */
117    public static function compare(string $dn, string $attributeName, string $value): CompareRequest
118    {
119        return new CompareRequest($dn, Filters::equal($attributeName, $value));
120    }
121
122    /**
123     * Delete an entry from LDAP by its DN.
124     */
125    public static function delete(string $dn): DeleteRequest
126    {
127        return new DeleteRequest($dn);
128    }
129
130    /**
131     * Perform an extended operation.
132     *
133     * @param null|AbstractType|ProtocolElementInterface|string $value
134     */
135    public static function extended(string $name, $value = null): ExtendedRequest
136    {
137        return new ExtendedRequest($name, $value);
138    }
139
140    /**
141     * Perform modification(s) on an LDAP entry.
142     */
143    public static function modify(string $dn, Change ...$changes): ModifyRequest
144    {
145        return new ModifyRequest($dn, ...$changes);
146    }
147
148    /**
149     * Move an LDAP entry to a new parent DN location.
150     *
151     * @throws UnexpectedValueException
152     */
153    public static function move(string $dn, string $newParentDn): ModifyDnRequest
154    {
155        $dnObj = new Dn($dn);
156
157        return new ModifyDnRequest($dn, $dnObj->getRdn()->toString(), true, $newParentDn);
158    }
159
160    /**
161     * Creates a password modify extended operation.
162     */
163    public static function passwordModify(string $username, string $oldPassword, string $newPassword): PasswordModifyRequest
164    {
165        return new PasswordModifyRequest($username, $oldPassword, $newPassword);
166    }
167
168    /**
169     * Quit is an alias for unbind. This is more indicative of what an unbind actually does.
170     */
171    public static function quit(): UnbindRequest
172    {
173        return self::unbind();
174    }
175
176    /**
177     * Rename an LDAP entry by modifying its RDN.
178     *
179     * @param string|Rdn $rdn
180     */
181    public static function rename(string $dn, $rdn, bool $deleteOldRdn = true): ModifyDnRequest
182    {
183        return new ModifyDnRequest($dn, $rdn, $deleteOldRdn);
184    }
185
186    /**
187     * Search LDAP with a given filter, scope, etc to retrieve a set of entries.
188     *
189     * @param string|Attribute ...$attributes
190     */
191    public static function search(FilterInterface $filter, ...$attributes): SearchRequest
192    {
193        return new SearchRequest($filter, ...$attributes);
194    }
195
196    /**
197     * Search for a specific base DN object to read. This sets a 'present' filter for the 'objectClass' attribute to help
198     * simplify it.
199     *
200     * @param string|Attribute ...$attributes
201     */
202    public static function read(string $baseDn, ...$attributes): SearchRequest
203    {
204        return (new SearchRequest(Filters::present('objectClass'), ...$attributes))->base($baseDn)->useBaseScope();
205    }
206
207    /**
208     * Search a single level list from a base DN object.
209     *
210     * @param string|Attribute ...$attributes
211     */
212    public static function list(FilterInterface $filter, string $baseDn, ...$attributes): SearchRequest
213    {
214        return (new SearchRequest($filter, ...$attributes))->base($baseDn)->useSingleLevelScope();
215    }
216
217    /**
218     * A request to unbind. This actually causes the server to terminate the client connection.
219     *
220     * @return UnbindRequest
221     */
222    public static function unbind(): UnbindRequest
223    {
224        return new UnbindRequest();
225    }
226
227    /**
228     * A request to determine who is currently authorized against LDAP for the current session.
229     *
230     * @return ExtendedRequest
231     */
232    public static function whoami(): ExtendedRequest
233    {
234        return new ExtendedRequest(ExtendedRequest::OID_WHOAMI);
235    }
236}
237