package org.dcache.gplazma.plugins;
import com.google.common.collect.Sets;
import org.globus.gsi.gssapi.jaas.GlobusPrincipal;
import org.hamcrest.Matcher;
import org.junit.Test;
import java.security.Principal;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import org.dcache.auth.FQANPrincipal;
import org.dcache.auth.GroupNamePrincipal;
import org.dcache.auth.UidPrincipal;
import org.dcache.auth.UserNamePrincipal;
import org.dcache.gplazma.AuthenticationException;
import org.dcache.gplazma.util.NameRolePair;
import static org.dcache.gplazma.plugins.PrincipalSetMaker.aSetOfPrincipals;
import static org.hamcrest.Matchers.hasItem;
import static org.hamcrest.Matchers.not;
import static org.junit.Assert.assertThat;
public class VoRoleMapPluginTest
{
private LineSource _source;
private VoRoleMapFileMaker _content;
private Set<Principal> _principals;
@Test(expected=NullPointerException.class)
public void shouldThrowNPEWhenGivenNullArgs() throws AuthenticationException
{
givenVoRoleMapFile().thatIsEmpty();
whenMapPluginCalledWith((Set<Principal>) null);
}
@Test
public void shouldAddPrimaryGroupWhenDnAndPrimaryFqanMatchEntryWithDnAndFqanWithNulls()
throws AuthenticationException
{
givenVoRoleMapFile().withSingleLine(
"\"/O=ACME/CN=Wile E Coyote\" \"/acme/Role=NULL/Capability=NULL\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
}
@Test
public void shouldAddPrimaryGroupWhenDnAndPrimaryFqanMatchEntryWithDnAndFqan()
throws AuthenticationException
{
givenVoRoleMapFile().
withSingleLine("\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
}
@Test
public void shouldIgnoreCommentAndAdditionalWhiteSpaceAndEmptyLines()
throws AuthenticationException
{
givenVoRoleMapFile().withLines(
"",
"# This is a comment, which should be ignored",
"",
" \t \"/O=ACME/CN=Wile E Coyote\" \t \"/acme\" acme01 \t # this is a comment",
"# this should be ignored, too");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
}
@Test
public void shouldAddGroupWhenDnAndFqanMatchEntryWithDnAndFqan()
throws AuthenticationException
{
givenVoRoleMapFile().
withSingleLine("\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme/Role=genius").
withFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme/Role=genius"));
assertThat(_principals, hasFqan("/acme"));
assertThat(_principals, hasGroupName("acme01")); // FIXME should be primaryGroupName?
}
@Test(expected=AuthenticationException.class)
public void shouldNotMatchWhenDnDoesNotMatchAndFqanMatches()
throws AuthenticationException
{
givenVoRoleMapFile().
withSingleLine("\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Road Runner").
withPrimaryFqan("/acme"));
}
@Test(expected=AuthenticationException.class)
public void shouldNotMatchWhenDnMatchesAndFqanDoesNotMatch()
throws AuthenticationException
{
givenVoRoleMapFile().
withSingleLine("\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/atlas"));
}
@Test
public void shouldAddGroupWithDnAndFqanWhenMatchesFirstLine()
throws AuthenticationException
{
givenVoRoleMapFile().withLines(
"\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01",
"\"/O=ACME/CN=Road Runner\" \"/acme\" acme02");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
assertThat(_principals, not(hasPrimaryGroupName("acme02")));
assertThat(_principals, not(hasGroupName("acme02")));
}
@Test
public void shouldAddGroupWithDnAndFqanWhenMatchesSecondLine()
throws AuthenticationException
{
givenVoRoleMapFile().withLines(
"\"/O=ACME/CN=Road Runner\" \"/acme\" acme02",
"\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
assertThat(_principals, not(hasPrimaryGroupName("acme02")));
assertThat(_principals, not(hasGroupName("acme02")));
}
@Test
public void shouldAddTwoGroupsWhenDnMatchesBothLinesAndTwoFqansEachMatchALineWithFirstLineMatchesPrimaryFqan()
throws AuthenticationException
{
givenVoRoleMapFile().withLines(
"\"/O=ACME/CN=Wile E Coyote\" \"/acme/Role=genius\" genius01",
"\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme/Role=genius").
withFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme/Role=genius"));
assertThat(_principals, hasFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("genius01"));
assertThat(_principals, not(hasGroupName("genius01")));
assertThat(_principals, not(hasPrimaryGroupName("acme01")));
assertThat(_principals, hasGroupName("acme01"));
}
@Test
public void shouldAddTwoGroupsWhenDnMatchesBothLinesAndTwoFqansEachMatchALineWithSecondLineMatchesPrimaryFqan()
throws AuthenticationException
{
givenVoRoleMapFile().withLines(
"\"/O=ACME/CN=Wile E Coyote\" \"/acme/Role=genius\" genius01",
"\"/O=ACME/CN=Wile E Coyote\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme").
withFqan("/acme/Role=genius"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasFqan("/acme/Role=genius"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
assertThat(_principals, not(hasPrimaryGroupName("genius01")));
assertThat(_principals, hasGroupName("genius01"));
}
@Test
public void shouldMatchUnquotedWildcardDnAndMatchingPrimaryFqan()
throws AuthenticationException
{
givenVoRoleMapFile().withSingleLine("* \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
}
@Test
public void shouldMatchQuotedWildcardDnAndMatchingPrimaryFqan()
throws AuthenticationException
{
givenVoRoleMapFile().withSingleLine("\"*\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
}
@Test
public void shouldMatchQuotedWildcardDnAndMatchingFqan()
throws AuthenticationException
{
givenVoRoleMapFile().withSingleLine("\"*\" \"/acme\" acme01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme/Role=genius").
withFqan("/acme"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme/Role=genius"));
assertThat(_principals, hasFqan("/acme"));
assertThat(_principals, hasGroupName("acme01")); // FIXME should be primaryGroupName
}
@Test
public void shouldHaveTwoMatchQuotedWildcardDnAndMatchingFqanAndPrimaryFqan()
throws AuthenticationException
{
givenVoRoleMapFile().withLines(
"\"*\" \"/acme\" acme01",
"\"*\" \"/acme/Role=genius\" genius01");
whenMapPluginCalledWith(aSetOfPrincipals().
withDn("/O=ACME/CN=Wile E Coyote").
withPrimaryFqan("/acme").
withFqan("/acme/Role=genius"));
assertThat(_principals, hasDn("/O=ACME/CN=Wile E Coyote"));
assertThat(_principals, hasPrimaryFqan("/acme"));
assertThat(_principals, hasFqan("/acme/Role=genius"));
assertThat(_principals, hasPrimaryGroupName("acme01"));
assertThat(_principals, not(hasGroupName("acme01")));
assertThat(_principals, not(hasPrimaryGroupName("genius01")));
assertThat(_principals, hasGroupName("genius01"));
}
@Test
public void shouldMatchLongestPrefixForPrimaryFqan() throws AuthenticationException
{
givenVoRoleMapFile().withLines(
"\"*\" \"/cms\" cms001");
whenMapPluginCalledWith(aSetOfPrincipals()
.withDn("/DC=es/DC=irisgrid/O=ciemat/CN=antonio-delgado-peris")
.withPrimaryFqan("/cms/escms")
.withFqan("/cms"));
assertThat(_principals, hasPrimaryGroupName("cms001"));
assertThat(_principals, hasDn("/DC=es/DC=irisgrid/O=ciemat/CN=antonio-delgado-peris"));
assertThat(_principals, hasPrimaryFqan("/cms/escms"));
}
public static Matcher<Iterable<? super GlobusPrincipal>> hasDn(String dn)
{
return hasItem(new GlobusPrincipal(dn));
}
public static Matcher<Iterable<? super UidPrincipal>> hasUid(int uid)
{
return hasItem(new UidPrincipal(uid));
}
public static Matcher<Iterable<? super FQANPrincipal>>
hasFqan(String fqan)
{
return hasItem(new FQANPrincipal(fqan));
}
public static Matcher<Iterable<? super FQANPrincipal>>
hasPrimaryFqan(String fqan)
{
return hasItem(new FQANPrincipal(fqan, true));
}
public static Matcher<Iterable<? super GroupNamePrincipal>>
hasGroupName(String group)
{
return hasItem(new GroupNamePrincipal(group));
}
public static Matcher<Iterable<? super UserNamePrincipal>>
hasUserName(String group)
{
return hasItem(new UserNamePrincipal(group));
}
public static Matcher<Iterable<? super GroupNamePrincipal>>
hasPrimaryGroupName(String group)
{
return hasItem(new GroupNamePrincipal(group, true));
}
private void whenMapPluginCalledWith(PrincipalSetMaker maker)
throws AuthenticationException
{
Set<Principal> principals = Sets.newHashSet(maker.build());
whenMapPluginCalledWith(principals);
}
private void whenMapPluginCalledWith(Set<Principal> principals) throws AuthenticationException
{
_principals = principals;
VOMapLineParser parser = new VOMapLineParser();
SourceBackedPredicateMap<NameRolePair,String> map =
new SourceBackedPredicateMap<>(_source,
parser);
GPlazmaMappingPlugin plugin = new VoRoleMapPlugin(map);
plugin.map(_principals);
}
private VoRoleMapFileMaker givenVoRoleMapFile()
{
_content = new VoRoleMapFileMaker();
return _content;
}
/** A builder for the content of a VoRoleMapFile with a fluent interface. */
private class VoRoleMapFileMaker
{
private final List<String> _lines = new LinkedList<>();
private VoRoleMapFileMaker()
{
update();
}
public VoRoleMapFileMaker thatIsEmpty()
{
_lines.clear();
update();
return this;
}
public VoRoleMapFileMaker withSingleLine(String line)
{
_lines.clear();
_lines.add(line);
update();
return this;
}
public VoRoleMapFileMaker withLines(String... line)
{
_lines.clear();
Collections.addAll(_lines, line);
update();
return this;
}
private void update()
{
_source = new MemoryLineSource(_lines);
}
}
}