Skip to content

Commit

Permalink
gplazma gridmap plugin: compare DNs ignoring letter case for attribut…
Browse files Browse the repository at this point in the history
…e names

Motivation:

GridMap plugin does string comparison of DNs stored in gridmap-file and
DN extracted from certificate. Apparently there is no requirement on
letter case in attribute names. This results in breaking string comparion
when attribute key names provided by certificate hadling libraries (CANL
in this case) do not match attribute names provided by the issuer.

Modification:

Massage DN strings to capitalize attribute names before comparison.

Result:

dCache works with certificates issued by InCommon CA that were noted to
contains attributes "postalCode" and "street" that do not match to CANL
provided "PostalCode" and "STREET" when forming string representation of
DN.

	Target: master
	Request: 5.0
	Request: 4.2
	Acked-by: Paul Millar <paul.millar@desy.de>
	Patch: https://rb.dcache.org/r/11561

	Require-book: no
	Require-notes: no
  • Loading branch information
DmitryLitvintsev committed Feb 22, 2019
1 parent 000bb8c commit eefd8ee
Showing 1 changed file with 79 additions and 12 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.dcache.gplazma.util;

import com.google.common.collect.ImmutableCollection;
import com.google.common.collect.ImmutableMultimap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
Expand All @@ -10,15 +9,54 @@
import java.io.FileReader;
import java.io.IOException;
import java.util.Collection;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

public class GridMapFile
{
private static final Logger _log =
private static final Logger LOGGER =
LoggerFactory.getLogger(GridMapFile.class);

private File _file;
private long _loaded;
private ImmutableMultimap<String,String> _map = ImmutableMultimap.of();

/**
* DNs are expected in openssl format: "/KEY1=value1/KEY2=value2"
*/

private static final Pattern KEY_PATTERN = Pattern.compile("/[^=]+=");

private static class DnUsername {
private String dn;
private String username;

DnUsername(String dn, String username) {
this.dn = dn;
this.username = username;
}

String getDn() {
return dn;
}

String getUsername() {
return username;
}

public String toString() {
return "(" + dn + "," + username + ")";
}

}

/**
* map that stores DN with attribute names in upper case as
* a key and pair (original dn, username) as value. This is needed
* to perform case insensitive match when comparing user DNs.
*/

private ImmutableMultimap<String, DnUsername> _map = ImmutableMultimap.of();

public GridMapFile(File file)
{
Expand All @@ -37,24 +75,24 @@ public synchronized void refresh()
long now = System.currentTimeMillis();
boolean readable = _file.canRead() || _loaded == 0;
if (!readable) {
_log.error("WARNING: Could not read grid-mapfile. Will use cached copy.");
LOGGER.error("WARNING: Could not read grid-mapfile. Will use cached copy.");
} else if (_loaded < _file.lastModified()) {
_log.debug("GridMapFileHandler reading {}", _file);
LOGGER.debug("GridMapFileHandler reading {}", _file);
try (BufferedReader reader = new BufferedReader(new FileReader(_file))) {
_map = read(reader);
_loaded = now;
}

}
} catch (IOException e) {
_log.error("Failed to load grid-mapfile: {}", e.getMessage());
LOGGER.error("Failed to load grid-mapfile: {}", e.getMessage());
}
}

private static ImmutableMultimap<String,String> read(BufferedReader reader)
private static ImmutableMultimap<String,DnUsername> read(BufferedReader reader)
throws IOException
{
ImmutableMultimap.Builder<String,String> map =
ImmutableMultimap.Builder<String,DnUsername> map =
ImmutableMultimap.builder();
String line;
while ((line = reader.readLine()) != null) {
Expand All @@ -70,7 +108,8 @@ private static ImmutableMultimap<String,String> read(BufferedReader reader)
String dn = line.substring(0, last_quote);
String user = line.substring(last_quote + 1).trim();
if (user != null && user.length() > 0) {
map.put(dn.trim(), removeQuotes(user.trim()));
map.put(capitalizeLabels(dn.trim()),
new DnUsername(dn.trim(), removeQuotes(user.trim())));
}
}
return map.build();
Expand All @@ -86,12 +125,40 @@ private static String removeQuotes(String quotedString)

public String getMappedUsername(String dn)
{
ImmutableCollection<String> names = _map.get(dn);
return names.isEmpty() ? null : names.asList().get(0);
Collection<String> names = getMappedUsernames(dn);
return names.isEmpty() ? null : names.iterator().next();
}

public Collection<String> getMappedUsernames(String dn)
{
return _map.get(dn);
/**
* input DN string needs to me massaged to capitalize attribute names
*/
Collection<DnUsername> dnNamePairs = _map.get(capitalizeLabels(dn));
if (!dnNamePairs.isEmpty() && LOGGER.isDebugEnabled()) {
LOGGER.debug("User DN \"{}\" matched to the following (DN, Username) pairs:\"{}",
dn,
dnNamePairs.stream()
.map(i -> i.toString())
.collect(Collectors.joining(",", "[", "]")));
}
Collection<String> names = dnNamePairs.stream()
.map(i->i.getUsername())
.collect(Collectors.toList());
return names;
}

private static String capitalizeLabels(String dn) {
Matcher m = KEY_PATTERN.matcher(dn);
StringBuilder output = new StringBuilder();
int i = 0;
while (m.find()) {
output.append(dn.substring(i, m.start()));
String label = m.group().toUpperCase();
output.append(label);
i = m.end();
}
output.append(dn.substring(i, dn.length()));
return output.toString();
}
}

0 comments on commit eefd8ee

Please sign in to comment.