/*
* Copyright (c) Members of the EGEE Collaboration. 2006-2010.
* See http://www.eu-egee.org/partners/ for details on the copyright holders.
*
* Licensed 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.glite.authz.pep.obligation.dfpmap;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import javax.security.auth.x500.X500Principal;
import org.glite.authz.common.fqan.FQAN;
import org.glite.authz.pep.obligation.ObligationProcessingException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* A strategy for mapping a subject's DN, primary and secondary FQANs to primary and secondary groups.
*/
public class DNFQANGroupNameMappingStrategy implements GroupNameMappingStrategy {
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(DNFQANGroupNameMappingStrategy.class);
/** DN/FQAN to POSIX group name mappings. */
private DFPM groupNameMapping;
/** Strategy to see if a {@link DFPM} key matches a given {@link FQAN}. */
private DFPMMatchStrategy<FQAN> fqanMatchStrategy;
/** Strategy to see if a {@link DFPM} key matches a given {@link X500Principal}. */
private DFPMMatchStrategy<X500Principal> dnMatchStrategy;
/** Whether to prefer a DN based mapping for the primary group name mapping. */
private boolean preferDNForPrimaryGroupName;
/**
* Constructor.
*
* @param groupMappings DN/FQAN to POSIX group name mappings, may not be null
* @param dnMatching strategy to see if a {@link DFPM} key matches a given {@link X500Principal}, may not be null
* @param fqanMatching strategy to see if a {@link DFPM} key matches a given {@link FQAN}, may not be null
* @param preferDNmappings whether to prefer a DN based mapping, over an FQAN based mapping, for the primary group
* name
*/
public DNFQANGroupNameMappingStrategy(DFPM groupMappings, DFPMMatchStrategy<X500Principal> dnMatching,
DFPMMatchStrategy<FQAN> fqanMatching, boolean preferDNmappings) {
if (groupMappings == null) {
throw new IllegalArgumentException("DN/FQAN to POSIX group mapping may not be null");
}
groupNameMapping = groupMappings;
if (dnMatching == null) {
throw new IllegalArgumentException("DN matching strategy may not be null");
}
dnMatchStrategy = dnMatching;
if (fqanMatching == null) {
throw new IllegalArgumentException("FQAN matching strategy may not be null");
}
fqanMatchStrategy = fqanMatching;
preferDNForPrimaryGroupName = preferDNmappings;
}
/** {@inheritDoc} */
public List<String> mapToGroupNames(X500Principal subjectDN, FQAN primaryFQAN, List<FQAN> secondaryFQANs)
throws ObligationProcessingException {
log.debug("Mapping group names for subject {} with primary FQAN {} and secondary FQANs {}", new Object[] {
subjectDN.getName(), primaryFQAN, secondaryFQANs });
List<String> dnGroupNames = new ArrayList<String>();
List<String> fqanGroupNames = new ArrayList<String>();
for (String mapKey : groupNameMapping.keySet()) {
if (groupNameMapping.isDNMapEntry(mapKey)) {
if (subjectDN != null) {
if (dnMatchStrategy.isMatch(mapKey, subjectDN)) {
List<String> grNames = groupNameMapping.get(mapKey);
dnGroupNames.addAll(grNames);
}
}
} else if (groupNameMapping.isFQANMapEntry(mapKey)) {
if (primaryFQAN != null) {
if (fqanMatchStrategy.isMatch(mapKey, primaryFQAN)) {
List<String> grNames = groupNameMapping.get(mapKey);
fqanGroupNames.addAll(grNames);
}
}
}
}
for (String mapKey : groupNameMapping.keySet()) {
if (groupNameMapping.isFQANMapEntry(mapKey)) {
if (secondaryFQANs != null) {
for (FQAN secondaryFQAN : secondaryFQANs) {
if (fqanMatchStrategy.isMatch(mapKey, secondaryFQAN)) {
List<String> grNames = groupNameMapping.get(mapKey);
fqanGroupNames.addAll(grNames);
}
}
}
}
}
List<String> groupNames = new ArrayList<String>();
if (log.isTraceEnabled()) {
log.trace("DN groups: {} FQAN groups: {}", dnGroupNames, fqanGroupNames);
}
if (preferDNForPrimaryGroupName) {
groupNames.addAll(dnGroupNames);
groupNames.addAll(fqanGroupNames);
} else {
groupNames.addAll(fqanGroupNames);
groupNames.addAll(dnGroupNames);
}
removeDuplicates(groupNames);
log.debug("Subject {} with primary FQAN {} and secondary FQANs {} mapped to group names: {}", new Object[] {
subjectDN.getName(), primaryFQAN, secondaryFQANs, groupNames });
return groupNames;
}
/**
* Removes duplicates names from the list. The first occurrence is retained.
*
* @param groupNames list of names from which duplicates should be removed.
*/
private void removeDuplicates(List<String> groupNames) {
HashSet<String> alreadySeen = new HashSet<String>();
String name;
Iterator<String> nameItr = groupNames.iterator();
while (nameItr.hasNext()) {
name = nameItr.next();
if (alreadySeen.contains(name)) {
nameItr.remove();
} else {
alreadySeen.add(name);
}
}
}
}