001/*
002 * The contents of this file are subject to the terms of the Common Development and
003 * Distribution License (the License). You may not use this file except in compliance with the
004 * License.
005 *
006 * You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the
007 * specific language governing permission and limitations under the License.
008 *
009 * When distributing Covered Software, include this CDDL Header Notice in each file and include
010 * the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL
011 * Header, with the fields enclosed by brackets [] replaced by your own identifying
012 * information: "Portions Copyright [year] [name of copyright owner]".
013 *
014 * Copyright 2013-2016 ForgeRock AS.
015 */
016package org.forgerock.opendj.adapter.server3x;
017
018import static com.forgerock.opendj.ldap.CoreMessages.*;
019import static com.forgerock.opendj.util.StaticUtils.*;
020
021import static org.forgerock.opendj.ldap.LdapException.*;
022import static org.opends.server.extensions.ExtensionsConstants.*;
023import static org.opends.server.util.CollectionUtils.*;
024
025import java.io.IOException;
026import java.util.ArrayList;
027import java.util.Collection;
028import java.util.Iterator;
029import java.util.List;
030
031import org.forgerock.i18n.LocalizableMessageBuilder;
032import org.forgerock.opendj.io.ASN1;
033import org.forgerock.opendj.io.ASN1Reader;
034import org.forgerock.opendj.io.ASN1Writer;
035import org.forgerock.opendj.ldap.Attribute;
036import org.forgerock.opendj.ldap.ByteString;
037import org.forgerock.opendj.ldap.ByteStringBuilder;
038import org.forgerock.opendj.ldap.DN;
039import org.forgerock.opendj.ldap.LdapException;
040import org.forgerock.opendj.ldap.LinkedAttribute;
041import org.forgerock.opendj.ldap.LinkedHashMapEntry;
042import org.forgerock.opendj.ldap.ResultCode;
043import org.forgerock.opendj.ldap.SearchScope;
044import org.forgerock.opendj.ldap.controls.Control;
045import org.forgerock.opendj.ldap.controls.GenericControl;
046import org.forgerock.opendj.ldap.responses.PasswordModifyExtendedResult;
047import org.forgerock.opendj.ldap.responses.Responses;
048import org.forgerock.opendj.ldap.responses.Result;
049import org.forgerock.opendj.ldap.responses.SearchResultEntry;
050import org.forgerock.opendj.server.config.meta.VirtualAttributeCfgDefn;
051import org.opends.server.core.BindOperation;
052import org.opends.server.core.CompareOperation;
053import org.opends.server.core.DirectoryServer;
054import org.opends.server.core.ExtendedOperation;
055import org.opends.server.protocols.ldap.LDAPAttribute;
056import org.opends.server.protocols.ldap.LDAPControl;
057import org.opends.server.protocols.ldap.LDAPFilter;
058import org.opends.server.protocols.ldap.LDAPModification;
059import org.opends.server.types.AttributeBuilder;
060import org.opends.server.types.DirectoryException;
061import org.opends.server.types.LDAPException;
062import org.opends.server.types.Operation;
063import org.opends.server.types.SearchFilter;
064import org.opends.server.util.ServerConstants;
065
066/** Common utility methods. */
067public final class Converters {
068
069    /** Prevent instantiation. */
070    private Converters() {
071        throw new AssertionError();
072    }
073
074    /**
075     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Entry} to OpenDJ
076     * server {@link org.opends.server.types.Entry}.
077     *
078     * @param sdkEntry
079     *          SDK entry to convert
080     * @return the converted entry
081     */
082    public static org.opends.server.types.Entry to(
083            final org.forgerock.opendj.ldap.Entry sdkEntry) {
084        if (sdkEntry != null) {
085            org.opends.server.types.Entry entry =
086                new org.opends.server.types.Entry(sdkEntry.getName(), null, null, null);
087            List<ByteString> duplicateValues = new ArrayList<>();
088            for (org.opends.server.types.Attribute attribute : toAttributes(sdkEntry.getAllAttributes())) {
089                if (attribute.getAttributeDescription().getAttributeType().isObjectClass()) {
090                    for (ByteString attrName : attribute) {
091                        try {
092                            entry.addObjectClass(DirectoryServer.getSchema().getObjectClass(attrName.toString()));
093                        } catch (DirectoryException e) {
094                            throw new IllegalStateException(e.getMessage(), e);
095                        }
096                    }
097                } else {
098                    entry.addAttribute(attribute, duplicateValues);
099                }
100            }
101            return entry;
102        }
103        return null;
104    }
105
106    /**
107     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.responses.SearchResultEntry} to OpenDJ
108     * server {@link org.opends.server.types.SearchResultEntry}.
109     *
110     * @param value
111     *          value to convert
112     * @return the converted value
113     */
114    public static org.opends.server.types.SearchResultEntry to(
115            final org.forgerock.opendj.ldap.responses.SearchResultEntry value) {
116        if (value != null) {
117            org.opends.server.types.Entry entry =
118                new org.opends.server.types.Entry(value.getName(), null, null, null);
119            org.opends.server.types.SearchResultEntry searchResultEntry =
120                new org.opends.server.types.SearchResultEntry(entry, to(value.getControls()));
121            List<ByteString> duplicateValues = new ArrayList<>();
122            for (org.opends.server.types.Attribute attribute : toAttributes(value.getAllAttributes())) {
123                searchResultEntry.addAttribute(attribute, duplicateValues);
124            }
125            return searchResultEntry;
126        }
127        return null;
128    }
129
130    /**
131     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Filter} to
132     * OpenDJ server {@link org.opends.server.types.RawFilter}.
133     *
134     * @param filter
135     *          value to convert
136     * @return the converted value
137     */
138    public static org.opends.server.types.RawFilter to(final org.forgerock.opendj.ldap.Filter filter) {
139        try {
140            return LDAPFilter.decode(filter.toString());
141        } catch (LDAPException e) {
142            throw new IllegalStateException(e);
143        }
144    }
145
146    /**
147     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Filter} to
148     * OpenDJ server {@link org.opends.server.types.RawFilter}.
149     *
150     * @param filter
151     *          value to convert
152     * @return the converted value
153     */
154    public static SearchFilter toSearchFilter(final org.forgerock.opendj.ldap.Filter filter) {
155        try {
156            return SearchFilter.createFilterFromString(filter.toString());
157        } catch (DirectoryException e) {
158            throw new IllegalStateException(e.getMessage(), e);
159        }
160    }
161
162    /**
163     * Converts from OpenDJ LDAP SDK
164     * {@link org.forgerock.opendj.ldap.responses.SearchResultReference} to OpenDJ
165     * server {@link org.opends.server.types.SearchResultReference}.
166     *
167     * @param searchResultReference
168     *          value to convert
169     * @return the converted value
170     */
171    public static org.opends.server.types.SearchResultReference to(
172            final org.forgerock.opendj.ldap.responses.SearchResultReference searchResultReference) {
173        return new org.opends.server.types.SearchResultReference(
174                searchResultReference.getURIs(), to(searchResultReference.getControls()));
175    }
176
177    /**
178     * Converts from OpenDJ LDAP SDK {@link Control} to OpenDJ server
179     * {@link org.opends.server.protocols.ldap.LDAPControl}.
180     *
181     * @param control
182     *          value to convert
183     * @return the converted value
184     */
185    public static org.opends.server.protocols.ldap.LDAPControl to(final Control control) {
186        return new LDAPControl(control.getOID(), control.isCritical(), control.getValue());
187    }
188
189    /**
190     * Converts from a <code>List</code> of OpenDJ LDAP SDK
191     * {@link org.forgerock.opendj.ldap.controls.Control} to a <code>List</code>
192     * of OpenDJ server {@link org.opends.server.types.Control}.
193     *
194     * @param listOfControl
195     *          value to convert
196     * @return the converted value
197     */
198    public static List<org.opends.server.types.Control> to(
199            final List<org.forgerock.opendj.ldap.controls.Control> listOfControl) {
200        List<org.opends.server.types.Control> toListOfControl = new ArrayList<>(listOfControl.size());
201        for (org.forgerock.opendj.ldap.controls.Control c : listOfControl) {
202            toListOfControl.add(to(c));
203        }
204        return toListOfControl;
205    }
206
207    /**
208     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}
209     * to OpenDJ server {@link org.opends.server.types.RawAttribute}.
210     *
211     * @param attribute
212     *          value to convert
213     * @return the converted value
214     */
215    public static org.opends.server.types.RawAttribute to(
216            final org.forgerock.opendj.ldap.Attribute attribute) {
217        ArrayList<ByteString> listAttributeValues = newArrayList(attribute.toArray());
218        return new LDAPAttribute(attribute.getAttributeDescriptionAsString(), listAttributeValues);
219    }
220
221    /**
222     * Converts from an <code>Iterable</code> of OpenDJ LDAP SDK
223     * {@link org.forgerock.opendj.ldap.Attribute} to a <code>List</code> of
224     * OpenDJ server {@link org.opends.server.types.RawAttribute}.
225     *
226     * @param listOfAttributes
227     *          value to convert
228     * @return the converted value
229     */
230    public static List<org.opends.server.types.RawAttribute> to(
231            final Iterable<org.forgerock.opendj.ldap.Attribute> listOfAttributes) {
232        List<org.opends.server.types.RawAttribute> toListOfAttributes =
233                new ArrayList<>(((Collection<?>) listOfAttributes).size());
234        for (org.forgerock.opendj.ldap.Attribute a : listOfAttributes) {
235            toListOfAttributes.add(to(a));
236        }
237        return toListOfAttributes;
238    }
239
240    /**
241     * Converts from OpenDJ LDAP SDK
242     * {@link org.forgerock.opendj.ldap.Modification} to OpenDJ server
243     * {@link org.opends.server.types.RawModification}.
244     *
245     * @param modification
246     *          value to convert
247     * @return the converted value
248     */
249    public static org.opends.server.types.RawModification to(
250            final org.forgerock.opendj.ldap.Modification modification) {
251        return new LDAPModification(modification.getModificationType(), to(modification
252                .getAttribute()));
253    }
254
255    /**
256     * Converts from a <code>List</code> of OpenDJ LDAP SDK
257     * {@link org.forgerock.opendj.ldap.Modification} to a <code>List</code> of
258     * OpenDJ server {@link org.opends.server.types.RawModification}.
259     *
260     * @param listOfModifications
261     *          value to convert
262     * @return the converted value
263     */
264    public static List<org.opends.server.types.RawModification> toRawModifications(
265            final List<org.forgerock.opendj.ldap.Modification> listOfModifications) {
266        List<org.opends.server.types.RawModification> toListOfModifications =
267                new ArrayList<>(listOfModifications.size());
268        for (org.forgerock.opendj.ldap.Modification m : listOfModifications) {
269            toListOfModifications.add(to(m));
270        }
271        return toListOfModifications;
272    }
273
274    /**
275     * Converts from OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}
276     * to OpenDJ server {@link org.opends.server.types.Attribute}.
277     *
278     * @param attribute
279     *          value to convert
280     * @return the converted value
281     */
282    public static org.opends.server.types.Attribute toAttribute(
283            final org.forgerock.opendj.ldap.Attribute attribute) {
284        final AttributeBuilder attrBuilder =
285            new AttributeBuilder(attribute.getAttributeDescriptionAsString());
286        for (ByteString b : attribute.toArray()) {
287            attrBuilder.add(b);
288        }
289        return attrBuilder.toAttribute();
290    }
291
292    /**
293     * Converts from an <code>Iterable</code> of OpenDJ LDAP SDK
294     * {@link org.forgerock.opendj.ldap.Attribute} to a <code>List</code> of
295     * OpenDJ server {@link org.opends.server.types.RawAttribute}.
296     *
297     * @param listOfAttributes
298     *          value to convert
299     * @return the converted value
300     */
301    public static List<org.opends.server.types.Attribute> toAttributes(
302            final Iterable<org.forgerock.opendj.ldap.Attribute> listOfAttributes) {
303        List<org.opends.server.types.Attribute> toListOfAttributes = new ArrayList<>();
304        Iterator<Attribute> it = listOfAttributes.iterator();
305        while (it.hasNext())
306        {
307          toListOfAttributes.add(toAttribute(it.next()));
308        }
309        return toListOfAttributes;
310    }
311
312    /**
313     * Converts from OpenDJ LDAP SDK
314     * {@link org.forgerock.opendj.ldap.Modification} to OpenDJ server
315     * {@link org.opends.server.types.Modification}.
316     *
317     * @param modification
318     *          value to convert
319     * @return the converted value
320     */
321    public static org.opends.server.types.Modification toModification(
322            final org.forgerock.opendj.ldap.Modification modification) {
323        return new org.opends.server.types.Modification(modification.getModificationType(),
324            toAttribute(modification.getAttribute()));
325    }
326
327    /**
328     * Converts from a <code>List</code> of OpenDJ LDAP SDK
329     * {@link org.forgerock.opendj.ldap.Modification} to a <code>List</code> of
330     * OpenDJ server {@link org.opends.server.types.Modification}.
331     *
332     * @param listOfModifications
333     *          value to convert
334     * @return the converted value
335     */
336    public static List<org.opends.server.types.Modification> toModifications(
337            final List<org.forgerock.opendj.ldap.Modification> listOfModifications) {
338        List<org.opends.server.types.Modification> toListOfModifications = new ArrayList<>(listOfModifications.size());
339        for (org.forgerock.opendj.ldap.Modification m : listOfModifications) {
340            toListOfModifications.add(toModification(m));
341        }
342        return toListOfModifications;
343    }
344
345    /**
346     * Converts from OpenDJ server
347     * {@link org.opends.server.protocols.ldap.LDAPControl} to OpenDJ LDAP SDK
348     * {@link Control}.
349     *
350     * @param ldapControl
351     *          value to convert
352     * @return the converted value
353     */
354    public static Control from(final org.opends.server.protocols.ldap.LDAPControl ldapControl) {
355        return GenericControl.newControl(ldapControl.getOID(), ldapControl.isCritical(),
356                ldapControl.getValue());
357    }
358
359    /**
360     * Converts from OpenDJ server {@link org.opends.server.types.Control} to
361     * OpenDJ LDAP SDK {@link Control}.
362     *
363     * @param control
364     *          value to convert
365     * @return the converted value
366     */
367    public static Control from(final org.opends.server.types.Control control) {
368        String oid = null;
369        boolean isCritical = false;
370        ByteString value = null;
371        // The server control doesn't have a method for extracting directly the value so, we need to ASN1 it.
372        ByteStringBuilder builder = new ByteStringBuilder();
373        final ASN1Writer writer = ASN1.getWriter(builder);
374        try {
375            control.write(writer);
376        } catch (IOException e) {
377            // Nothing to do.
378        }
379
380        final ByteString sdkByteString = builder.toByteString();
381        final org.forgerock.opendj.io.ASN1Reader sdkReaderASN1 =
382                org.forgerock.opendj.io.ASN1.getReader(sdkByteString.toByteArray());
383
384        // Reads the ASN1 SDK byte string.
385        try {
386            sdkReaderASN1.readStartSequence();
387            oid = sdkReaderASN1.readOctetStringAsString();
388            if (sdkReaderASN1.hasNextElement()
389                    && sdkReaderASN1.peekType() == ASN1.UNIVERSAL_BOOLEAN_TYPE) {
390                isCritical = sdkReaderASN1.readBoolean();
391            }
392            if (sdkReaderASN1.hasNextElement()
393                    && sdkReaderASN1.peekType() == ASN1.UNIVERSAL_OCTET_STRING_TYPE) {
394                value = sdkReaderASN1.readOctetString();
395            }
396            sdkReaderASN1.readEndSequence();
397        } catch (IOException e) {
398            // Nothing to do.
399        }
400        // Creates the control
401        return GenericControl.newControl(oid, isCritical, value);
402    }
403
404    /**
405     * Converts from a <code>List</code> of OpenDJ server
406     * {@link org.opends.server.types.Control} to a <code>List</code> of OpenDJ
407     * LDAP SDK {@link org.forgerock.opendj.ldap.controls.Control}.
408     *
409     * @param listOfControl
410     *          value to convert
411     * @return the converted value
412     */
413    public static List<org.forgerock.opendj.ldap.controls.Control> from(
414            final List<org.opends.server.types.Control> listOfControl) {
415        List<org.forgerock.opendj.ldap.controls.Control> fromListofControl = new ArrayList<>(listOfControl.size());
416        for (org.opends.server.types.Control c : listOfControl) {
417            fromListofControl.add(from(c));
418        }
419        return fromListofControl;
420    }
421
422    /**
423     * Converts from OpenDJ server
424     * {@link org.opends.server.types.SearchResultReference} to OpenDJ LDAP SDK
425     * {@link org.forgerock.opendj.ldap.responses.SearchResultReference}.
426     *
427     * @param srvResultReference
428     *          value to convert
429     * @return the converted value
430     */
431    public static org.forgerock.opendj.ldap.responses.SearchResultReference from(
432            final org.opends.server.types.SearchResultReference srvResultReference) {
433        return Responses.newSearchResultReference(srvResultReference.getReferralURLString());
434    }
435
436    /**
437     * Converts from OpenDJ server {@link org.opends.server.types.Attribute} to
438     * OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}.
439     *
440     * @param attribute
441     *          value to convert
442     * @return the converted value
443     */
444    public static org.forgerock.opendj.ldap.Attribute from(
445            final org.opends.server.types.Attribute attribute) {
446        Attribute sdkAttribute = new LinkedAttribute(attribute.getAttributeDescription());
447        for (ByteString value : attribute) {
448            sdkAttribute.add(value);
449        }
450        return sdkAttribute;
451    }
452
453    /**
454     * Converts from an <code>Iterable</code> of OpenDJ server
455     * {@link org.opends.server.types.Attribute} to a <code>List</code> of OpenDJ
456     * LDAP SDK {@link org.forgerock.opendj.ldap.Attribute}.
457     *
458     * @param listOfAttributes
459     *          value to convert
460     * @return the converted value
461     */
462    public static List<org.forgerock.opendj.ldap.Attribute> from(
463            final Iterable<org.opends.server.types.Attribute> listOfAttributes) {
464        List<org.forgerock.opendj.ldap.Attribute> fromListofAttributes =
465                new ArrayList<>(((Collection<?>) listOfAttributes).size());
466        for (org.opends.server.types.Attribute a : listOfAttributes) {
467            fromListofAttributes.add(from(a));
468        }
469        return fromListofAttributes;
470    }
471
472    /**
473     * Converts from OpenDJ server
474     * {@link org.opends.server.types.SearchResultEntry} to OpenDJ LDAP SDK
475     * {@link org.forgerock.opendj.ldap.responses.SearchResultEntry}.
476     *
477     * @param srvResultEntry
478     *          value to convert
479     * @return the converted value
480     */
481    public static org.forgerock.opendj.ldap.responses.SearchResultEntry from(
482            final org.opends.server.types.SearchResultEntry srvResultEntry) {
483
484        final SearchResultEntry searchResultEntry =
485                Responses.newSearchResultEntry(srvResultEntry.getName().toString());
486        for (org.opends.server.types.Attribute a : srvResultEntry.getAttributes()) {
487            searchResultEntry.addAttribute(from(a));
488        }
489        for (org.opends.server.types.Control c : srvResultEntry.getControls()) {
490            searchResultEntry.addControl(from(c));
491        }
492        return searchResultEntry;
493    }
494
495    /**
496     * Converts from OpenDJ server
497     * {@link org.opends.server.types.Entry} to OpenDJ LDAP SDK
498     * {@link org.forgerock.opendj.ldap.Entry}.
499     *
500     * @param srvResultEntry
501     *          value to convert
502     * @return the converted value
503     */
504    public static org.forgerock.opendj.ldap.Entry from(
505        final org.opends.server.types.Entry srvResultEntry) {
506
507        final org.forgerock.opendj.ldap.Entry entry = new LinkedHashMapEntry(srvResultEntry.getName().toString());
508        entry.addAttribute(from(srvResultEntry.getObjectClassAttribute()));
509        for (org.opends.server.types.Attribute a : srvResultEntry.getAttributes()) {
510            entry.addAttribute(from(a));
511        }
512        return entry;
513    }
514
515    /**
516     * Converts from OpenDJ server
517     * {@link org.forgerock.opendj.server.config.meta.VirtualAttributeCfgDefn.Scope}
518     *  to OpenDJ LDAP SDK {@link org.forgerock.opendj.ldap.SearchScope}.
519     *
520     * @param srvScope
521     *          The server scope value.
522     * @return The SDK scope value.
523     */
524    public static SearchScope from(VirtualAttributeCfgDefn.Scope srvScope) {
525        if (srvScope != null) {
526            switch (srvScope) {
527            case BASE_OBJECT:
528                return SearchScope.BASE_OBJECT;
529            case SINGLE_LEVEL:
530                return SearchScope.SINGLE_LEVEL;
531            case SUBORDINATE_SUBTREE:
532                return SearchScope.SUBORDINATES;
533            case WHOLE_SUBTREE:
534                return SearchScope.WHOLE_SUBTREE;
535            default:
536                return null;
537            }
538        }
539        return null;
540    }
541
542    /**
543     * Populates the result object with the operation details and return the
544     * result object if it was successful. Otherwise, it throws an
545     * {@link LdapException}.
546     *
547     * @param <T>
548     *          the type of the result object
549     * @param operation
550     *          used to populate the result
551     * @param result
552     *          the result object to populate from the Operation
553     * @return the result if successful, an {@link LdapException} is thrown
554     *         otherwise
555     * @throws LdapException
556     *           when an error occurs
557     */
558    public static <T extends Result> T getResponseResult(final Operation operation, final T result)
559            throws LdapException {
560        if (operation.getReferralURLs() != null) {
561            for (String ref : operation.getReferralURLs()) {
562                result.addReferralURI(ref);
563            }
564        }
565        if (operation.getResponseControls() != null) {
566            for (org.opends.server.types.Control c : operation.getResponseControls()) {
567                result.addControl(from(c));
568            }
569        }
570        final LocalizableMessageBuilder errorMsg = operation.getErrorMessage();
571        final DN matchedDN = operation.getMatchedDN();
572        result.setDiagnosticMessage(errorMsg != null ? errorMsg.toString() : null);
573        result.setMatchedDN(matchedDN != null ? matchedDN.toString() : null);
574        if (result.isSuccess()) {
575            return result;
576        } else {
577            throw newLdapException(result);
578        }
579    }
580
581    /**
582     * Converts the OpenDJ server {@link Operation} object into an OpenDJ LDAP SDK
583     * {@link Result} object.
584     *
585     * @param operation
586     *          value to convert
587     * @return the converted value
588     * @throws LdapException
589     *           when an error occurs
590     */
591    public static Result getResponseResult(final Operation operation) throws LdapException {
592        return getResponseResult(operation, newSDKResult(operation));
593    }
594
595    private static Result newSDKResult(final Operation operation) throws LdapException {
596        ResultCode rc = operation.getResultCode();
597        if (operation instanceof BindOperation) {
598            return Responses.newBindResult(rc);
599        } else if (operation instanceof CompareOperation) {
600            return Responses.newCompareResult(rc);
601        } else if (operation instanceof ExtendedOperation) {
602            ExtendedOperation extendedOperation = (ExtendedOperation) operation;
603            switch (extendedOperation.getRequestOID()) {
604            case ServerConstants.OID_PASSWORD_MODIFY_REQUEST:
605                PasswordModifyExtendedResult result = Responses.newPasswordModifyExtendedResult(rc);
606                ByteString generatedPwd = getGeneratedPassword(extendedOperation);
607                if (generatedPwd != null) {
608                    result.setGeneratedPassword(generatedPwd.toByteArray());
609                }
610                return result;
611
612            default:
613                return Responses.newGenericExtendedResult(rc);
614            }
615        }
616        return Responses.newResult(rc);
617    }
618
619    private static ByteString getGeneratedPassword(ExtendedOperation op) throws LdapException {
620        // FIXME this code is duplicated with code in the SDK
621        // see PasswordModifyExtendedRequestImpl#ResultDecoder#decodeExtendedResult()
622        ByteString responseValue = op.getResponseValue();
623        if (responseValue != null) {
624            try {
625                ASN1Reader reader = ASN1.getReader(responseValue);
626                reader.readStartSequence();
627                return reader.readOctetString(TYPE_PASSWORD_MODIFY_GENERATED_PASSWORD);
628            } catch (IOException e) {
629                throw LdapException.newLdapException(ResultCode.PROTOCOL_ERROR,
630                        ERR_EXTOP_PASSMOD_CANNOT_DECODE_REQUEST.get(getExceptionMessage(e)), e);
631            }
632        }
633        return null;
634    }
635
636    /**
637     * Converts from <code>byte[]</code> to OpenDJ server {@link ByteString}.
638     *
639     * @param authenticationValue
640     *          value to convert
641     * @return the converted value
642     */
643    public static ByteString getCredentials(final byte[] authenticationValue) {
644        final ASN1Reader reader = ASN1.getReader(authenticationValue);
645        try {
646            reader.readOctetStringAsString(); // Reads SASL Mechanism - RFC 4511 4.2
647            if (reader.hasNextElement()) {
648                return reader.readOctetString().toByteString();
649            }
650        } catch (IOException e) {
651            // Nothing to do.
652        }
653        return ByteString.empty();
654    }
655}