001 /**************************************************************** 002 * Licensed to the Apache Software Foundation (ASF) under one * 003 * or more contributor license agreements. See the NOTICE file * 004 * distributed with this work for additional information * 005 * regarding copyright ownership. The ASF licenses this file * 006 * to you under the Apache License, Version 2.0 (the * 007 * "License"); you may not use this file except in compliance * 008 * with the License. You may obtain a copy of the License at * 009 * * 010 * http://www.apache.org/licenses/LICENSE-2.0 * 011 * * 012 * Unless required by applicable law or agreed to in writing, * 013 * software distributed under the License is distributed on an * 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * 015 * KIND, either express or implied. See the License for the * 016 * specific language governing permissions and limitations * 017 * under the License. * 018 ****************************************************************/ 019 020 package org.apache.james.jspf.policies.local; 021 022 import org.apache.james.jspf.core.Logger; 023 import org.apache.james.jspf.core.SPF1Record; 024 import org.apache.james.jspf.core.SPFRecordParser; 025 import org.apache.james.jspf.core.exceptions.NeutralException; 026 import org.apache.james.jspf.core.exceptions.NoneException; 027 import org.apache.james.jspf.core.exceptions.PermErrorException; 028 import org.apache.james.jspf.core.exceptions.SPFResultException; 029 import org.apache.james.jspf.core.exceptions.TempErrorException; 030 import org.apache.james.jspf.policies.PolicyPostFilter; 031 032 import java.util.Collections; 033 import java.util.HashMap; 034 import java.util.Iterator; 035 import java.util.Map; 036 037 /** 038 * Class to support Fallback feature 039 */ 040 public class FallbackPolicy implements PolicyPostFilter { 041 042 private Map<String,SPF1Record> entryMap; 043 044 private SPFRecordParser parser; 045 046 private Logger log; 047 048 public FallbackPolicy(Logger log, SPFRecordParser parser) { 049 this.log = log; 050 entryMap = Collections.synchronizedMap(new HashMap<String,SPF1Record>()); 051 this.parser = parser; 052 } 053 054 /** 055 * Add a entry. 056 * 057 * @param rawHost 058 * the host or ipaddress for which the entry should be added. 059 * @param rawSpfRecord 060 * the spfRecord to add 061 * @throws IllegalArgumentException 062 * get thrown on invalid spfRecord 063 */ 064 public void addEntry(String rawHost, String rawSpfRecord) 065 throws IllegalArgumentException { 066 String host; 067 try { 068 log.debug("Start parsing SPF-Record: " + rawSpfRecord); 069 SPF1Record spfRecord = parser.parse(rawSpfRecord); 070 if (rawHost.startsWith("*")) { 071 host = rawHost.substring(1); 072 log.debug("Convert host " + rawHost + " to " + host); 073 } else if (rawHost.endsWith("*")) { 074 int length = rawHost.length(); 075 host = rawHost.substring(length - 1, length); 076 log.debug("Convert host " + rawHost + " to " + host); 077 } else { 078 host = rawHost; 079 } 080 081 entryMap.put(host, spfRecord); 082 } catch (SPFResultException e) { 083 throw new IllegalArgumentException("Invalid SPF-Record: " 084 + rawSpfRecord); 085 } 086 087 } 088 089 /** 090 * Clear all entries 091 * 092 */ 093 public void clearEntrys() { 094 log.debug("Clear all entries"); 095 entryMap.clear(); 096 } 097 098 /** 099 * Remove entry 100 * 101 * @param host 102 * The host 103 */ 104 public void removeEntry(String host) { 105 log.debug("Remove fallback entry for host: " + host); 106 synchronized (entryMap) { 107 entryMap.remove(getRawEntry(host)); 108 } 109 } 110 111 /** 112 * @see org.apache.james.jspf.policies.PolicyPostFilter#getSPFRecord(java.lang.String, org.apache.james.jspf.core.SPF1Record) 113 */ 114 public SPF1Record getSPFRecord(String currentDomain, SPF1Record res) throws PermErrorException, TempErrorException, NoneException, NeutralException { 115 if (res == null) { 116 return getMySPFRecord(currentDomain); 117 } else { 118 return res; 119 } 120 } 121 122 /** 123 * Return the SPF1Record for the given host 124 * 125 * @param host 126 * the hostname or ipaddress 127 * @return the SPF1Record of null if no SPF1Record was found in fallback for 128 * the given host 129 */ 130 protected SPF1Record getMySPFRecord(String host) { 131 SPF1Record entry = null; 132 133 synchronized (entryMap) { 134 entry = getRawEntry(host); 135 } 136 137 if (entry != null) { 138 return entry; 139 } else { 140 return null; 141 } 142 } 143 144 /** 145 * Return the Object stored in the map which match the given host. Keep in 146 * mind that this method should only called in a synchronized method or 147 * block 148 * 149 * @param host 150 * the host 151 * @return the stored object for the given host or null 152 */ 153 private SPF1Record getRawEntry(String host) { 154 Iterator<String> fallBackIt = entryMap.keySet().iterator(); 155 156 while (fallBackIt.hasNext()) { 157 String rawHost = fallBackIt.next(); 158 159 if ((rawHost.startsWith(".") && host.startsWith(rawHost)) 160 || rawHost.endsWith(".") && host.endsWith(rawHost)) { 161 return entryMap.get(rawHost); 162 } 163 } 164 return null; 165 } 166 167 }