View Javadoc

1   /**
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements. See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    *
10   * http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied. See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  package org.apache.ws.security.util;
20  
21  import java.io.IOException;
22  import java.io.StringReader;
23  
24  public class RFC2253Parser {
25      
26      /**
27       * Method rfc2253toXMLdsig
28       *
29       * @param dn
30       * @return normalized string
31       */
32      public static String rfc2253toXMLdsig(String dn) {
33          // Transform from RFC1779 to RFC2253
34          String normalized = normalize(dn, true);
35  
36          return rfctoXML(normalized);
37      }
38  
39      /**
40       * Method xmldsigtoRFC2253
41       *
42       * @param dn
43       * @return normalized string
44       */
45      public static String xmldsigtoRFC2253(String dn) {
46          // Transform from RFC1779 to RFC2253
47          String normalized = normalize(dn, false);
48  
49          return xmltoRFC(normalized);
50      }
51  
52      /**
53       * Method normalize
54       *
55       * @param dn
56       * @return normalized string
57       */
58      public static String normalize(String dn) {
59          return normalize(dn, true);
60      }
61      
62      /**
63       * Method normalize
64       *
65       * @param dn
66       * @param toXml
67       * @return normalized string
68       */
69      public static String normalize(String dn, boolean toXml) {
70          //if empty string
71          if ((dn == null) || dn.equals("")) {
72              return "";
73          }
74  
75          try {
76              String DN = semicolonToComma(dn);
77              StringBuilder sb = new StringBuilder();
78              int i = 0;
79              int l = 0;
80              int k;
81  
82              //for name component
83              for (int j = 0; (k = DN.indexOf(',', j)) >= 0; j = k + 1) {
84                  l += countQuotes(DN, j, k);
85  
86                  if ((k > 0) && (DN.charAt(k - 1) != '\\') && (l % 2) == 0) {
87                      sb.append(parseRDN(DN.substring(i, k).trim(), toXml)).append(",");
88  
89                      i = k + 1;
90                      l = 0;
91                  }
92              }
93  
94              sb.append(parseRDN(trim(DN.substring(i)), toXml));
95  
96              return sb.toString();
97          } catch (IOException ex) {
98              return dn;
99          }
100     }
101 
102     /**
103      * Method parseRDN
104      *
105      * @param str
106      * @param toXml
107      * @return normalized string
108      * @throws IOException
109      */
110     static String parseRDN(String str, boolean toXml) throws IOException {
111         StringBuilder sb = new StringBuilder();
112         int i = 0;
113         int l = 0;
114         int k;
115 
116         for (int j = 0; (k = str.indexOf('+', j)) >= 0; j = k + 1) {
117             l += countQuotes(str, j, k);
118 
119             if ((k > 0) && (str.charAt(k - 1) != '\\') && (l % 2) == 0) {
120                 sb.append(parseATAV(trim(str.substring(i, k)), toXml)).append("+");
121 
122                 i = k + 1;
123                 l = 0;
124             }
125         }
126 
127         sb.append(parseATAV(trim(str.substring(i)), toXml));
128 
129         return sb.toString();
130     }
131 
132     /**
133      * Method parseATAV
134      *
135      * @param str
136      * @param toXml
137      * @return normalized string
138      * @throws IOException
139      */
140     static String parseATAV(String str, boolean toXml) throws IOException {
141         int i = str.indexOf('=');
142 
143         if ((i == -1) || ((i > 0) && (str.charAt(i - 1) == '\\'))) {
144             return str;
145         } 
146         String attrType = normalizeAT(str.substring(0, i));
147         // only normalize if value is a String
148         String attrValue = null;
149         if (attrType.charAt(0) >= '0' && attrType.charAt(0) <= '9') {
150             attrValue = str.substring(i + 1);
151         } else {
152             attrValue = normalizeV(str.substring(i + 1), toXml);
153         }
154 
155         return attrType + "=" + attrValue;
156 
157     }
158 
159     /**
160      * Method normalizeAT
161      *
162      * @param str
163      * @return normalized string
164      */
165     static String normalizeAT(String str) {
166 
167         String at = str.toUpperCase().trim();
168 
169         if (at.startsWith("OID")) {
170             at = at.substring(3);
171         }
172 
173         return at;
174     }
175 
176     /**
177      * Method normalizeV
178      *
179      * @param str
180      * @param toXml
181      * @return normalized string
182      * @throws IOException
183      */
184     static String normalizeV(String str, boolean toXml) throws IOException {
185         String value = trim(str);
186 
187         if (value.startsWith("\"")) {
188             StringBuilder sb = new StringBuilder();
189             StringReader sr = new StringReader(value.substring(1, value.length() - 1));
190             int i = 0;
191             char c;
192 
193             while ((i = sr.read()) > -1) {
194                 c = (char) i;
195 
196                 //the following char is defined at 4.Relationship with RFC1779 and LDAPv2 inrfc2253
197                 if ((c == ',') || (c == '=') || (c == '+') || (c == '<')
198                     || (c == '>') || (c == '#') || (c == ';')) {
199                     sb.append('\\');
200                 }
201 
202                 sb.append(c);
203             }
204 
205             value = trim(sb.toString());
206         }
207 
208         if (toXml) {
209             if (value.startsWith("#")) {
210                 value = '\\' + value;
211             }
212         } else {
213             if (value.startsWith("\\#")) {
214                 value = value.substring(1);
215             }
216         }
217 
218         return value;
219     }
220 
221     /**
222      * Method rfctoXML
223      *
224      * @param string
225      * @return normalized string
226      */
227     static String rfctoXML(String string) {
228         try {
229             String s = changeLess32toXML(string);
230 
231             return changeWStoXML(s);
232         } catch (Exception e) {
233             return string;
234         }
235     }
236 
237     /**
238      * Method xmltoRFC
239      *
240      * @param string
241      * @return normalized string
242      */
243     static String xmltoRFC(String string) {
244         try {
245             String s = changeLess32toRFC(string);
246 
247             return changeWStoRFC(s);
248         } catch (Exception e) {
249             return string;
250         }
251     }
252 
253     /**
254      * Method changeLess32toRFC
255      *
256      * @param string
257      * @return normalized string
258      * @throws IOException
259      */
260     static String changeLess32toRFC(String string) throws IOException {
261         StringBuilder sb = new StringBuilder();
262         StringReader sr = new StringReader(string);
263         int i = 0;
264         char c;
265 
266         while ((i = sr.read()) > -1) {
267             c = (char) i;
268 
269             if (c == '\\') {
270                 sb.append(c);
271 
272                 char c1 = (char) sr.read();
273                 char c2 = (char) sr.read();
274 
275                 //65 (A) 97 (a)
276                 if ((((c1 >= 48) && (c1 <= 57)) || ((c1 >= 65) && (c1 <= 70)) || ((c1 >= 97) && (c1 <= 102)))
277                     && (((c2 >= 48) && (c2 <= 57))
278                         || ((c2 >= 65) && (c2 <= 70))
279                         || ((c2 >= 97) && (c2 <= 102)))) {
280                     char ch = (char) Byte.parseByte("" + c1 + c2, 16);
281 
282                     sb.append(ch);
283                 } else {
284                     sb.append(c1);
285                     sb.append(c2);
286                 }
287             } else {
288                 sb.append(c);
289             }
290         }
291 
292         return sb.toString();
293     }
294 
295     /**
296      * Method changeLess32toXML
297      *
298      * @param string
299      * @return normalized string
300      * @throws IOException
301      */
302     static String changeLess32toXML(String string) throws IOException {
303         StringBuilder sb = new StringBuilder();
304         StringReader sr = new StringReader(string);
305         int i = 0;
306 
307         while ((i = sr.read()) > -1) {
308             if (i < 32) {
309                 sb.append('\\');
310                 sb.append(Integer.toHexString(i));
311             } else {
312                 sb.append((char) i);
313             }
314         }
315 
316         return sb.toString();
317     }
318 
319     /**
320      * Method changeWStoXML
321      *
322      * @param string
323      * @return normalized string
324      * @throws IOException
325      */
326     static String changeWStoXML(String string) throws IOException {
327         StringBuilder sb = new StringBuilder();
328         StringReader sr = new StringReader(string);
329         int i = 0;
330         char c;
331 
332         while ((i = sr.read()) > -1) {
333             c = (char) i;
334 
335             if (c == '\\') {
336                 char c1 = (char) sr.read();
337 
338                 if (c1 == ' ') {
339                     sb.append('\\');
340 
341                     String s = "20";
342 
343                     sb.append(s);
344                 } else {
345                     sb.append('\\');
346                     sb.append(c1);
347                 }
348             } else {
349                 sb.append(c);
350             }
351         }
352 
353         return sb.toString();
354     }
355 
356     /**
357      * Method changeWStoRFC
358      *
359      * @param string
360      * @return normalized string
361      */
362     static String changeWStoRFC(String string) {
363         StringBuilder sb = new StringBuilder();
364         int i = 0;
365         int k;
366 
367         for (int j = 0; (k = string.indexOf("\\20", j)) >= 0; j = k + 3) {
368             sb.append(trim(string.substring(i, k))).append("\\ ");
369 
370             i = k + 3;
371         }
372 
373         sb.append(string.substring(i));
374 
375         return sb.toString();
376     }
377 
378     /**
379      * Method semicolonToComma
380      *
381      * @param str
382      * @return normalized string
383      */
384     static String semicolonToComma(String str) {
385         return removeWSandReplace(str, ";", ",");
386     }
387 
388     /**
389      * Method removeWhiteSpace
390      *
391      * @param str
392      * @param symbol
393      * @return normalized string
394      */
395     static String removeWhiteSpace(String str, String symbol) {
396         return removeWSandReplace(str, symbol, symbol);
397     }
398 
399     /**
400      * Method removeWSandReplace
401      *
402      * @param str
403      * @param symbol
404      * @param replace
405      * @return normalized string
406      */
407     static String removeWSandReplace(String str, String symbol, String replace) {
408         StringBuilder sb = new StringBuilder();
409         int i = 0;
410         int l = 0;
411         int k;
412 
413         for (int j = 0; (k = str.indexOf(symbol, j)) >= 0; j = k + 1) {
414             l += countQuotes(str, j, k);
415 
416             if ((k > 0) && (str.charAt(k - 1) != '\\') && (l % 2) == 0) {
417                 sb.append(trim(str.substring(i, k))).append(replace);
418 
419                 i = k + 1;
420                 l = 0;
421             }
422         }
423 
424         sb.append(trim(str.substring(i)));
425 
426         return sb.toString();
427     }
428 
429     /**
430      * Returns the number of Quotation from i to j
431      *
432      * @param s
433      * @param i
434      * @param j
435      * @return number of quotes
436      */
437     private static int countQuotes(String s, int i, int j) {
438         int k = 0;
439 
440         for (int l = i; l < j; l++) {
441             if (s.charAt(l) == '"') {
442                 k++;
443             }
444         }
445 
446         return k;
447     }
448 
449     //only for the end of a space character occurring at the end of the string from rfc2253
450 
451     /**
452      * Method trim
453      *
454      * @param str
455      * @return the string
456      */
457     static String trim(String str) {
458 
459         String trimed = str.trim();
460         int i = str.indexOf(trimed) + trimed.length();
461 
462         if ((str.length() > i) && trimed.endsWith("\\")
463             && !trimed.endsWith("\\\\") && (str.charAt(i) == ' ')) {
464             trimed = trimed + " ";
465         }
466 
467         return trimed;
468     }
469 
470 }