001    /**
002     * Licensed to the Apache Software Foundation (ASF) under one or more
003     * contributor license agreements.  See the NOTICE file distributed with
004     * this work for additional information regarding copyright ownership.
005     * The ASF licenses this file to You under the Apache License, Version 2.0
006     * (the "License"); you may not use this file except in compliance with
007     * the License.  You may obtain a copy of the License at
008     *
009     *     http://www.apache.org/licenses/LICENSE-2.0
010     *
011     * Unless required by applicable law or agreed to in writing, software
012     * distributed under the License is distributed on an "AS IS" BASIS,
013     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014     * See the License for the specific language governing permissions and
015     * limitations under the License.
016     */
017    
018    package org.apache.geronimo.javamail.authentication;
019    
020    import java.lang.reflect.Constructor;
021    import java.util.List;
022    import java.util.Properties;
023    
024    import org.apache.geronimo.javamail.util.ProtocolProperties; 
025    
026    public class AuthenticatorFactory {
027        // the list of authentication mechanisms we have direct support for.  Others come from 
028        // SASL, if it's available. 
029        
030        public static final String AUTHENTICATION_PLAIN = "PLAIN";
031        public static final String AUTHENTICATION_LOGIN = "LOGIN";
032        public static final String AUTHENTICATION_CRAMMD5 = "CRAM-MD5";
033        public static final String AUTHENTICATION_DIGESTMD5 = "DIGEST-MD5";
034         
035        static public ClientAuthenticator getAuthenticator(ProtocolProperties props, List mechanisms, String host, String username, String password, String authId, String realm)
036        {
037            // if the authorization id isn't given, then this is the same as the logged in user name. 
038            if (authId == null) {
039                authId = username; 
040            }
041            
042            // if SASL is enabled, try getting a SASL authenticator first 
043            if (props.getBooleanProperty("sasl.enable", false)) {
044                // we need to convert the mechanisms map into an array of strings for SASL. 
045                String [] mechs = (String [])mechanisms.toArray(new String[mechanisms.size()]); 
046                
047                try {
048                    // need to try to load this using reflection since it has references to 
049                    // the SASL API.  That's only available with 1.5 or later. 
050                    Class authenticatorClass = Class.forName("org.apache.geronimo.javamal.authentication.SASLAuthenticator"); 
051                    Constructor c = authenticatorClass.getConstructor(new Class[] {
052                        (new String[0]).getClass(), 
053                        Properties.class, 
054                        String.class, 
055                        String.class, 
056                        String.class, 
057                        String.class, 
058                        String.class, 
059                        String.class
060                    }); 
061                    
062                    Object[] args = { mechs, props.getProperties(), props.getProtocol(), host, realm, authId, username, password };
063                    
064                    return (ClientAuthenticator)c.newInstance(args); 
065                } catch (Throwable e) {
066                    // Any exception is likely because we're running on 1.4 and can't use the Sasl API.  
067                    // just ignore and use our fallback implementations. 
068                }
069            }
070    
071            // now go through the progression of mechanisms we support, from the
072            // most secure to the least secure.
073    
074            if (mechanisms.contains(AUTHENTICATION_DIGESTMD5)) {
075                return new DigestMD5Authenticator(host, username, password, realm);
076            } else if (mechanisms.contains(AUTHENTICATION_CRAMMD5)) {
077                return new CramMD5Authenticator(username, password);
078            } else if (mechanisms.contains(AUTHENTICATION_LOGIN)) {
079                return new LoginAuthenticator(username, password);
080            } else if (mechanisms.contains(AUTHENTICATION_PLAIN)) {
081                return new PlainAuthenticator(username, password);
082            } else {
083                // can't find a mechanism we support in common
084                return null;
085            }
086        }
087    }
088