1 package org
.argeo
.util
.naming
;
3 import java
.io
.BufferedReader
;
4 import java
.io
.IOException
;
5 import java
.io
.InputStream
;
6 import java
.io
.InputStreamReader
;
8 import java
.nio
.charset
.Charset
;
9 import java
.nio
.charset
.StandardCharsets
;
10 import java
.util
.ArrayList
;
11 import java
.util
.Base64
;
12 import java
.util
.List
;
13 import java
.util
.SortedMap
;
14 import java
.util
.TreeMap
;
16 import javax
.naming
.InvalidNameException
;
17 import javax
.naming
.NamingException
;
18 import javax
.naming
.directory
.Attribute
;
19 import javax
.naming
.directory
.Attributes
;
20 import javax
.naming
.directory
.BasicAttribute
;
21 import javax
.naming
.directory
.BasicAttributes
;
22 import javax
.naming
.ldap
.LdapName
;
23 import javax
.naming
.ldap
.Rdn
;
25 import org
.argeo
.osgi
.useradmin
.UserDirectoryException
;
27 /** Basic LDIF parser. */
28 public class LdifParser
{
29 private final static Charset DEFAULT_CHARSET
= StandardCharsets
.UTF_8
;
31 protected Attributes
addAttributes(SortedMap
<LdapName
, Attributes
> res
, int lineNumber
, LdapName currentDn
,
32 Attributes currentAttributes
) {
34 Rdn nameRdn
= currentDn
.getRdn(currentDn
.size() - 1);
35 Attribute nameAttr
= currentAttributes
.get(nameRdn
.getType());
37 currentAttributes
.put(nameRdn
.getType(), nameRdn
.getValue());
38 else if (!nameAttr
.get().equals(nameRdn
.getValue()))
39 throw new UserDirectoryException(
40 "Attribute " + nameAttr
.getID() + "=" + nameAttr
.get() + " not consistent with DN " + currentDn
41 + " (shortly before line " + lineNumber
+ " in LDIF file)");
42 Attributes previous
= res
.put(currentDn
, currentAttributes
);
44 } catch (NamingException e
) {
45 throw new UserDirectoryException("Cannot add " + currentDn
, e
);
49 /** With UTF-8 charset */
50 public SortedMap
<LdapName
, Attributes
> read(InputStream in
) throws IOException
{
51 try (Reader reader
= new InputStreamReader(in
, DEFAULT_CHARSET
)) {
56 } catch (IOException e
) {
62 /** Will close the reader. */
63 public SortedMap
<LdapName
, Attributes
> read(Reader reader
) throws IOException
{
64 SortedMap
<LdapName
, Attributes
> res
= new TreeMap
<LdapName
, Attributes
>();
66 List
<String
> lines
= new ArrayList
<>();
67 try (BufferedReader br
= new BufferedReader(reader
)) {
69 while ((line
= br
.readLine()) != null) {
73 if (lines
.size() == 0)
75 // add an empty new line since the last line is not checked
76 if (!lines
.get(lines
.size() - 1).equals(""))
79 LdapName currentDn
= null;
80 Attributes currentAttributes
= null;
81 StringBuilder currentEntry
= new StringBuilder();
83 readLines
: for (int lineNumber
= 0; lineNumber
< lines
.size(); lineNumber
++) {
84 String line
= lines
.get(lineNumber
);
85 boolean isLastLine
= false;
86 if (lineNumber
== lines
.size() - 1)
88 if (line
.startsWith(" ")) {
89 currentEntry
.append(line
.substring(1));
94 if (currentEntry
.length() != 0 || isLastLine
) {
95 // read previous attribute
96 StringBuilder attrId
= new StringBuilder(8);
97 boolean isBase64
= false;
98 readAttrId
: for (int i
= 0; i
< currentEntry
.length(); i
++) {
99 char c
= currentEntry
.charAt(i
);
101 if (i
+ 1 < currentEntry
.length() && currentEntry
.charAt(i
+ 1) == ':')
103 currentEntry
.delete(0, i
+ (isBase64 ?
2 : 1));
110 String attributeId
= attrId
.toString();
111 // TODO should we really trim the end of the string as well?
112 String cleanValueStr
= currentEntry
.toString().trim();
113 Object attributeValue
= isBase64 ? Base64
.getDecoder().decode(cleanValueStr
) : cleanValueStr
;
115 // manage DN attributes
116 if (attributeId
.equals(LdapAttrs
.DN
) || isLastLine
) {
117 if (currentDn
!= null) {
121 Attributes previous
= addAttributes(res
, lineNumber
, currentDn
, currentAttributes
);
122 if (previous
!= null) {
123 // log.warn("There was already an entry with DN " + currentDn
124 // + ", which has been discarded by a subsequent one.");
128 if (attributeId
.equals(LdapAttrs
.DN
))
130 currentDn
= new LdapName(attributeValue
.toString());
131 currentAttributes
= new BasicAttributes(true);
132 } catch (InvalidNameException e
) {
133 // log.error(attributeValue + " not a valid DN, skipping the entry.");
135 currentAttributes
= null;
140 if (currentAttributes
!= null) {
141 Attribute attribute
= currentAttributes
.get(attributeId
);
142 if (attribute
== null) {
143 attribute
= new BasicAttribute(attributeId
);
144 currentAttributes
.put(attribute
);
146 attribute
.add(attributeValue
);
148 currentEntry
= new StringBuilder();
150 currentEntry
.append(line
);
155 } catch (IOException e
) {