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    package org.apache.james.protocols.smtp.core;
020    
021    import java.util.Locale;
022    
023    import org.apache.james.protocols.smtp.SMTPRetCode;
024    import org.apache.james.protocols.smtp.SMTPSession;
025    import org.apache.james.protocols.smtp.dsn.DSNStatus;
026    import org.apache.james.protocols.smtp.hook.HookResult;
027    import org.apache.james.protocols.smtp.hook.HookReturnCode;
028    import org.apache.james.protocols.smtp.hook.RcptHook;
029    import org.apache.mailet.MailAddress;
030    
031    /**
032     * Handler which check if the authenticated user is the same as the one used as MAIL FROM
033     */
034    public abstract class AbstractSenderAuthIdentifyVerificationRcptHook implements RcptHook {  
035        /**
036         * @see org.apache.james.protocols.smtp.hook.RcptHook#doRcpt(org.apache.james.protocols.smtp.SMTPSession,
037         *      org.apache.mailet.MailAddress, org.apache.mailet.MailAddress)
038         */
039        public HookResult doRcpt(SMTPSession session, MailAddress sender,
040                MailAddress rcpt) {
041            if (session.getUser() != null) {
042                String authUser = (session.getUser()).toLowerCase(Locale.US);
043                MailAddress senderAddress = (MailAddress) session.getState().get(
044                        SMTPSession.SENDER);
045                String username= null;
046    
047                if (senderAddress != null) {
048                    if (useVirtualHosting()) {
049                        username = senderAddress.toString();
050                    } else {
051                        username = senderAddress.getLocalPart();
052                    }
053                }
054                
055                // Check if the sender address is the same as the user which was used to authenticate.
056                // Its important to ignore case here to fix JAMES-837. This is save todo because if the handler is called
057                // the user was already authenticated
058                if ((senderAddress == null)
059                        || (!authUser.equalsIgnoreCase(username))
060                        || (!isLocalDomain(senderAddress.getDomain()))) {
061                    return new HookResult(HookReturnCode.DENY, 
062                            SMTPRetCode.BAD_SEQUENCE,
063                            DSNStatus.getStatus(DSNStatus.PERMANENT,
064                                    DSNStatus.SECURITY_AUTH)
065                                    + " Incorrect Authentication for Specified Email Address");
066                }
067            }
068            return new HookResult(HookReturnCode.DECLINED);
069        }
070        
071        
072        /**
073         * Return true if the given domain is a local domain for this server
074         * 
075         * @param domain
076         * @return isLocal
077         */
078        protected abstract boolean isLocalDomain(String domain);
079        
080        /**
081         * Return true if virtualHosting should get used. If so the full email address will get used to 
082         * match against the supplied auth username
083         * 
084         * @return useVirtualHosting
085         */
086        protected abstract boolean useVirtualHosting();
087    
088    }