blob: 83e96921f946ac1524d310b3adc217afb667b175 [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.xml.security.utils;
import java.io.IOException;
import java.io.StringReader;
public class RFC2253Parser {
/**
* Method rfc2253toXMLdsig
*
* @param dn
* @return normalized string
*/
public static String rfc2253toXMLdsig(String dn) {
// Transform from RFC1779 to RFC2253
String normalized = normalize(dn, true);
return rfctoXML(normalized);
}
/**
* Method xmldsigtoRFC2253
*
* @param dn
* @return normalized string
*/
public static String xmldsigtoRFC2253(String dn) {
// Transform from RFC1779 to RFC2253
String normalized = normalize(dn, false);
return xmltoRFC(normalized);
}
/**
* Method normalize
*
* @param dn
* @return normalized string
*/
public static String normalize(String dn) {
return normalize(dn, true);
}
/**
* Method normalize
*
* @param dn
* @param toXml
* @return normalized string
*/
public static String normalize(String dn, boolean toXml) {
//if empty string
if (dn == null || dn.isEmpty()) {
return "";
}
try {
String DN = semicolonToComma(dn);
StringBuilder sb = new StringBuilder();
int i = 0;
int l = 0;
int k;
//for name component
for (int j = 0; (k = DN.indexOf(',', j)) >= 0; j = k + 1) {
l += countQuotes(DN, j, k);
if (k > 0 && DN.charAt(k - 1) != '\\' && (l % 2) == 0) {
sb.append(parseRDN(DN.substring(i, k).trim(), toXml)).append(',');
i = k + 1;
l = 0;
}
}
sb.append(parseRDN(trim(DN.substring(i)), toXml));
return sb.toString();
} catch (IOException ex) {
return dn;
}
}
/**
* Method parseRDN
*
* @param str
* @param toXml
* @return normalized string
* @throws IOException
*/
static String parseRDN(String str, boolean toXml) throws IOException {
StringBuilder sb = new StringBuilder();
int i = 0;
int l = 0;
int k;
for (int j = 0; (k = str.indexOf('+', j)) >= 0; j = k + 1) {
l += countQuotes(str, j, k);
if (k > 0 && str.charAt(k - 1) != '\\' && (l % 2) == 0) {
sb.append(parseATAV(trim(str.substring(i, k)), toXml)).append('+');
i = k + 1;
l = 0;
}
}
sb.append(parseATAV(trim(str.substring(i)), toXml));
return sb.toString();
}
/**
* Method parseATAV
*
* @param str
* @param toXml
* @return normalized string
* @throws IOException
*/
static String parseATAV(String str, boolean toXml) throws IOException {
int i = str.indexOf('=');
if (i == -1 || i > 0 && str.charAt(i - 1) == '\\') {
return str;
}
String attrType = normalizeAT(str.substring(0, i));
// only normalize if value is a String
String attrValue = null;
if (attrType.charAt(0) >= '0' && attrType.charAt(0) <= '9') {
attrValue = str.substring(i + 1);
} else {
attrValue = normalizeV(str.substring(i + 1), toXml);
}
return attrType + "=" + attrValue;
}
/**
* Method normalizeAT
*
* @param str
* @return normalized string
*/
static String normalizeAT(String str) {
String at = str.toUpperCase().trim();
if (at.startsWith("OID")) {
at = at.substring(3);
}
return at;
}
/**
* Method normalizeV
*
* @param str
* @param toXml
* @return normalized string
* @throws IOException
*/
static String normalizeV(String str, boolean toXml) throws IOException {
String value = trim(str);
if (value.startsWith("\"")) {
StringBuilder sb = new StringBuilder();
StringReader sr = new StringReader(value.substring(1, value.length() - 1));
int i = 0;
char c;
while ((i = sr.read()) > -1) {
c = (char) i;
//the following char is defined at 4.Relationship with RFC1779 and LDAPv2 inrfc2253
if (c == ',' || c == '=' || c == '+' || c == '<'
|| c == '>' || c == '#' || c == ';') {
sb.append('\\');
}
sb.append(c);
}
value = trim(sb.toString());
}
if (toXml) {
if (value.length() > 0 && value.charAt(0) == '#') {
value = '\\' + value;
}
} else {
if (value.startsWith("\\#")) {
value = value.substring(1);
}
}
return value;
}
/**
* Method rfctoXML
*
* @param string
* @return normalized string
*/
static String rfctoXML(String string) {
try {
String s = changeLess32toXML(string);
return changeWStoXML(s);
} catch (Exception e) {
return string;
}
}
/**
* Method xmltoRFC
*
* @param string
* @return normalized string
*/
static String xmltoRFC(String string) {
try {
String s = changeLess32toRFC(string);
return changeWStoRFC(s);
} catch (Exception e) {
return string;
}
}
/**
* Method changeLess32toRFC
*
* @param string
* @return normalized string
* @throws IOException
*/
static String changeLess32toRFC(String string) throws IOException {
StringBuilder sb = new StringBuilder();
StringReader sr = new StringReader(string);
int i = 0;
char c;
while ((i = sr.read()) > -1) {
c = (char) i;
if (c == '\\') {
sb.append(c);
char c1 = (char) sr.read();
char c2 = (char) sr.read();
//65 (A) 97 (a)
if ((c1 >= 48 && c1 <= 57 || c1 >= 65 && c1 <= 70 || c1 >= 97 && c1 <= 102)
&& (c2 >= 48 && c2 <= 57
|| c2 >= 65 && c2 <= 70
|| c2 >= 97 && c2 <= 102)) {
char ch = (char) Byte.parseByte("" + c1 + c2, 16);
sb.append(ch);
} else {
sb.append(c1);
sb.append(c2);
}
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* Method changeLess32toXML
*
* @param string
* @return normalized string
* @throws IOException
*/
static String changeLess32toXML(String string) throws IOException {
StringBuilder sb = new StringBuilder();
StringReader sr = new StringReader(string);
int i = 0;
while ((i = sr.read()) > -1) {
if (i < 32) {
sb.append('\\');
sb.append(Integer.toHexString(i));
} else {
sb.append((char) i);
}
}
return sb.toString();
}
/**
* Method changeWStoXML
*
* @param string
* @return normalized string
* @throws IOException
*/
static String changeWStoXML(String string) throws IOException {
StringBuilder sb = new StringBuilder();
StringReader sr = new StringReader(string);
int i = 0;
char c;
while ((i = sr.read()) > -1) {
c = (char) i;
if (c == '\\') {
char c1 = (char) sr.read();
if (c1 == ' ') {
sb.append('\\');
String s = "20";
sb.append(s);
} else {
sb.append('\\');
sb.append(c1);
}
} else {
sb.append(c);
}
}
return sb.toString();
}
/**
* Method changeWStoRFC
*
* @param string
* @return normalized string
*/
static String changeWStoRFC(String string) {
StringBuilder sb = new StringBuilder();
int i = 0;
int k;
for (int j = 0; (k = string.indexOf("\\20", j)) >= 0; j = k + 3) {
sb.append(trim(string.substring(i, k))).append("\\ ");
i = k + 3;
}
sb.append(string.substring(i));
return sb.toString();
}
/**
* Method semicolonToComma
*
* @param str
* @return normalized string
*/
static String semicolonToComma(String str) {
return removeWSandReplace(str, ";", ",");
}
/**
* Method removeWhiteSpace
*
* @param str
* @param symbol
* @return normalized string
*/
static String removeWhiteSpace(String str, String symbol) {
return removeWSandReplace(str, symbol, symbol);
}
/**
* Method removeWSandReplace
*
* @param str
* @param symbol
* @param replace
* @return normalized string
*/
static String removeWSandReplace(String str, String symbol, String replace) {
StringBuilder sb = new StringBuilder();
int i = 0;
int l = 0;
int k;
for (int j = 0; (k = str.indexOf(symbol, j)) >= 0; j = k + 1) {
l += countQuotes(str, j, k);
if (k > 0 && str.charAt(k - 1) != '\\' && (l % 2) == 0) {
sb.append(trim(str.substring(i, k))).append(replace);
i = k + 1;
l = 0;
}
}
sb.append(trim(str.substring(i)));
return sb.toString();
}
/**
* Returns the number of Quotation from i to j
*
* @param s
* @param i
* @param j
* @return number of quotes
*/
private static int countQuotes(String s, int i, int j) {
int k = 0;
for (int l = i; l < j; l++) {
if (s.charAt(l) == '"') {
k++;
}
}
return k;
}
//only for the end of a space character occurring at the end of the string from rfc2253
/**
* Method trim
*
* @param str
* @return the string
*/
static String trim(String str) {
String trimed = str.trim();
int i = str.indexOf(trimed) + trimed.length();
if (str.length() > i && trimed.endsWith("\\")
&& !trimed.endsWith("\\\\") && str.charAt(i) == ' ') {
trimed = trimed + " ";
}
return trimed;
}
}