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 LoginAuthenticator implements ClientAuthenticator {
027    
028        // constants for the authentication stages
029        protected static final int USERNAME = 0;
030    
031        protected static final int PASSWORD = 1;
032    
033        protected static final int COMPLETE = 2;
034    
035        // the user we're authenticating
036        protected String username;
037    
038        // the user's password (the "shared secret")
039        protected String password;
040    
041        // indicates whether we've gone through the entire challenge process.
042        protected int stage = USERNAME;
043    
044        /**
045         * Main constructor.
046         * 
047         * @param username
048         *            The login user name.
049         * @param password
050         *            The login password.
051         */
052        public LoginAuthenticator(String username, String password) {
053            this.username = username;
054            this.password = password;
055        }
056    
057        /**
058         * Respond to the hasInitialResponse query. This mechanism does not have an
059         * initial response.
060         * 
061         * @return Always returns false;
062         */
063        public boolean hasInitialResponse() {
064            return false;
065        }
066    
067        /**
068         * Indicate whether the challenge/response process is complete.
069         * 
070         * @return True if the last challenge has been processed, false otherwise.
071         */
072        public boolean isComplete() {
073            return stage == COMPLETE;
074        }
075    
076        /**
077         * Retrieve the authenticator mechanism name.
078         * 
079         * @return Always returns the string "LOGIN"
080         */
081        public String getMechanismName() {
082            return "LOGIN";
083        }
084    
085        /**
086         * Evaluate a PLAIN login challenge, returning the a result string that
087         * should satisfy the clallenge.
088         * 
089         * @param challenge
090         *            The decoded challenge data, as a byte array
091         * 
092         * @return A formatted challege response, as an array of bytes.
093         * @exception MessagingException
094         */
095        public byte[] evaluateChallenge(byte[] challenge) throws MessagingException {
096    
097            // process the correct stage for the challenge
098            switch (stage) {
099            // should never happen
100            case COMPLETE:
101                throw new MessagingException("Invalid LOGIN challenge");
102    
103            case USERNAME: {
104                byte[] userBytes;
105    
106                try {
107                    // get the username and password in an UTF-8 encoding to create
108                    // the token
109                    userBytes = username.getBytes("UTF-8");
110                } catch (UnsupportedEncodingException e) {
111                    // got an error, fail this (this should never happen).
112                    throw new MessagingException("Invalid encoding");
113                }
114    
115                // next time through we're looking for a password.
116                stage = PASSWORD;
117                // the user bytes are the entire challenge respose.
118                return userBytes;
119            }
120    
121            case PASSWORD: {
122                byte[] passBytes;
123    
124                try {
125                    // get the username and password in an UTF-8 encoding to create
126                    // the token
127                    passBytes = password.getBytes("UTF-8");
128                } catch (UnsupportedEncodingException e) {
129                    // got an error, fail this (this should never happen).
130                    throw new MessagingException("Invalid encoding");
131                }
132                // we're finished
133                stage = COMPLETE;
134                return passBytes;
135            }
136            }
137            // should never get here.
138            throw new MessagingException("Invalid LOGIN challenge");
139        }
140    }