/* * 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.HashMap; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.security.auth.x500.X500Principal; import org.glite.authz.pep.obligation.ObligationProcessingException; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * An in-memory manager for pool accounts. * * This implementation is not generally useful in production environments but is useful for testing and to provide an * example of the various steps and checks needed when doing pool account management without having to worry about the * underlying persistent store. */ public class MemoryBackedPoolAcountManager implements PoolAccountManager { /** Class logger. */ private final Logger log = LoggerFactory.getLogger(MemoryBackedPoolAcountManager.class); /** Managed pool accounts indexed by prefix. */ private HashMap<String, List<String>> managedAccounts; /** Current assigned accounts. Indexes are of the form dn{:primary_group_name{:secondary_group_name}*}? */ private HashMap<String, String> currentAccountMappings; /** * Constructor. * * @param managedAccounts pool accounts to be managed */ public MemoryBackedPoolAcountManager(List<String> poolAccounts) { managedAccounts = new HashMap<String, List<String>>(); currentAccountMappings = new HashMap<String, String>(); if (poolAccounts != null) { Pattern accountPrefixPat = Pattern.compile("^(\\p{Alpha}*)\\p{Digit}*$"); Matcher prefixMatcher; String prefix; for (String account : poolAccounts) { prefixMatcher = accountPrefixPat.matcher(account); if (prefixMatcher.find()) { prefix = prefixMatcher.group(1); if (prefix != null) { addManagedPoolAccount(prefix, account); } else { log.warn("{} did not contain a valid pool account name prefix, ignoring it"); } } else { log.warn("{} is not a valid pool account name, ignoring it"); } } } } /** {@inheritDoc} */ public List<String> getPoolAccountNamePrefixes() { return new ArrayList<String>(managedAccounts.keySet()); } /** {@inheritDoc} */ public List<String> getPoolAccountNames() { ArrayList<String> allManagedAccounts = new ArrayList<String>(); for (List<String> accountSet : managedAccounts.values()) { allManagedAccounts.addAll(accountSet); } return allManagedAccounts; } /** {@inheritDoc} */ public List<String> getPoolAccountNames(String prefix) { return managedAccounts.get(prefix); } /** {@inheritDoc} */ public boolean isPoolAccountPrefix(String accountIndicator) { return accountIndicator.startsWith("."); } /** {@inheritDoc} */ public String getPoolAccountPrefix(String accountIndicator) { if(isPoolAccountPrefix(accountIndicator)){ return accountIndicator.substring(1); } return null; } /** {@inheritDoc} */ public synchronized String mapToAccount(String accountNamePrefix, X500Principal subjectDN, String primaryGroup, List<String> secondaryGroups) throws ObligationProcessingException { if(accountNamePrefix.startsWith(".")){ accountNamePrefix = accountNamePrefix.substring(1); } log.debug("Mapping subject {} with primary group {} and secondary groups {} to a pool account with prefix {}", new Object[] { subjectDN.getName(), primaryGroup, secondaryGroups, accountNamePrefix }); String accountMappingKey = createAccountMappingKey(subjectDN, primaryGroup, secondaryGroups); String loginName = currentAccountMappings.get(accountMappingKey); if (loginName != null) { log.debug("Subject {} has an existing account mapping to account {}", subjectDN.getName(), loginName); if (!loginName.startsWith(accountNamePrefix)) { log.error("Subject " + subjectDN.getName() + " has an existing mapping to account " + loginName + " but this account name does not start with the pool account name prefix, " + accountNamePrefix + ", to which they were mapped."); throw new ObligationProcessingException("Error with existing pool account mapping for this subject"); } return loginName; } List<String> managedAccounts = getPoolAccountNames(accountNamePrefix); if (managedAccounts == null) { return null; } log.debug("Subject {} does not have an existing pool account mapping, attempting to create a new one", subjectDN.getName()); for (String account : managedAccounts) { if (!currentAccountMappings.values().contains(account)) { log.debug("Subject {} given a new pool account mapping to account {}", subjectDN.getName(), account); loginName = account; currentAccountMappings.put(accountMappingKey, account); return loginName; } } log.warn("No pool account, with prefix {}, available to which {} could be mapped", accountNamePrefix, subjectDN .getName()); return null; } /** * Creates an account mapping key associated with a pool account. The key is in the form: * canonical_dn{:primary_group_name{:secondary_group_names}*}? * * @param subjectDN DN of the subject * @param primaryGroup name of the subject's primary group * @param secondaryGroups names of the subject's secondary groups * * @return the constructed account mapping key */ private String createAccountMappingKey(X500Principal subjectDN, String primaryGroup, List<String> secondaryGroups) { StringBuilder builder = new StringBuilder(subjectDN.getName(X500Principal.CANONICAL)); if (primaryGroup != null) { builder.append(":").append(primaryGroup); if (secondaryGroups != null) { for (String name : secondaryGroups) { builder.append(":").append(name); } } } return builder.toString(); } /** * Adds a pool account to the list of managed accounts. * * @param prefix the pool account name prefix * @param loginName the pool account name */ private void addManagedPoolAccount(String prefix, String loginName) { if (!loginName.startsWith(prefix)) { throw new IllegalArgumentException("Account name " + loginName + " does not begin with the provided pool account name prefix " + prefix); } List<String> accounts = managedAccounts.get(prefix); if (accounts == null) { accounts = new ArrayList<String>(); managedAccounts.put(prefix, accounts); } accounts.add(loginName); } }