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.geronimo.javamail.authentication;
021    
022    import java.io.UnsupportedEncodingException;
023    
024    import javax.mail.MessagingException;
025    
026    public class PlainAuthenticator implements ClientAuthenticator {
027    
028        // the user we're authenticating
029        protected String username;
030    
031        // the user's password (the "shared secret")
032        protected String password;
033    
034        // indicates whether we've gone through the entire challenge process.
035        protected boolean complete = false;
036    
037        /**
038         * Main constructor.
039         * 
040         * @param username
041         *            The login user name.
042         * @param password
043         *            The login password.
044         */
045        public PlainAuthenticator(String username, String password) {
046            this.username = username;
047            this.password = password;
048        }
049    
050        /**
051         * Respond to the hasInitialResponse query. This mechanism does have an
052         * initial response, which is the entire challenge sequence.
053         * 
054         * @return Always returns true.
055         */
056        public boolean hasInitialResponse() {
057            return true;
058        }
059    
060        /**
061         * Indicate whether the challenge/response process is complete.
062         * 
063         * @return True if the last challenge has been processed, false otherwise.
064         */
065        public boolean isComplete() {
066            return complete;
067        }
068    
069        /**
070         * Retrieve the authenticator mechanism name.
071         * 
072         * @return Always returns the string "PLAIN"
073         */
074        public String getMechanismName() {
075            return "PLAIN";
076        }
077    
078        /**
079         * Evaluate a PLAIN login challenge, returning the a result string that
080         * should satisfy the clallenge.
081         * 
082         * @param challenge
083         *            The decoded challenge data, as byte array.
084         * 
085         * @return A formatted challege response, as an array of bytes.
086         * @exception MessagingException
087         */
088        public byte[] evaluateChallenge(byte[] challenge) throws MessagingException {
089            try {
090                // get the username and password in an UTF-8 encoding to create the
091                // token
092                byte[] userBytes = username.getBytes("UTF-8");
093                byte[] passBytes = password.getBytes("UTF-8");
094    
095                // our token has two copies of the username, one copy of the
096                // password, and nulls
097                // between
098                byte[] tokenBytes = new byte[(userBytes.length * 2) + passBytes.length + 2];
099    
100                System.arraycopy(userBytes, 0, tokenBytes, 0, userBytes.length);
101                System.arraycopy(userBytes, 0, tokenBytes, userBytes.length + 1, userBytes.length);
102                System.arraycopy(passBytes, 0, tokenBytes, (userBytes.length * 2) + 2, passBytes.length);
103    
104                complete = true;
105                return tokenBytes;
106    
107            } catch (UnsupportedEncodingException e) {
108                // got an error, fail this
109                throw new MessagingException("Invalid encoding");
110            }
111        }
112    }