1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package org.apache.james.smtpserver.core;
23
24 import org.apache.james.dsn.DSNStatus;
25 import org.apache.james.smtpserver.CommandHandler;
26 import org.apache.james.smtpserver.SMTPSession;
27 import org.apache.james.util.codec.Base64;
28 import org.apache.avalon.framework.logger.AbstractLogEnabled;
29
30 import java.util.ArrayList;
31 import java.util.Collection;
32 import java.util.Locale;
33 import java.util.StringTokenizer;
34 import java.io.IOException;
35
36
37
38
39
40 public class AuthCmdHandler
41 extends AbstractLogEnabled
42 implements CommandHandler {
43
44
45
46
47 private final static String AUTH_TYPE_PLAIN = "PLAIN";
48
49
50
51
52 private final static String AUTH_TYPE_LOGIN = "LOGIN";
53
54
55
56
57
58
59 public void onCommand(SMTPSession session) {
60
61
62 try{
63 doAUTH(session, session.getCommandArgument());
64 } catch (Exception ex) {
65 getLogger().error("Exception occured:" + ex.getMessage());
66 session.endSession();
67 }
68 }
69
70
71
72
73
74
75
76
77
78
79 private void doAUTH(SMTPSession session, String argument)
80 throws Exception {
81 String responseString = null;
82 if (session.getUser() != null) {
83 responseString = "503 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_OTHER)+" User has previously authenticated. "
84 + " Further authentication is not required!";
85 session.writeResponse(responseString);
86 } else if (argument == null) {
87 responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" Usage: AUTH (authentication type) <challenge>";
88 session.writeResponse(responseString);
89 } else {
90 String initialResponse = null;
91 if ((argument != null) && (argument.indexOf(" ") > 0)) {
92 initialResponse = argument.substring(argument.indexOf(" ") + 1);
93 argument = argument.substring(0,argument.indexOf(" "));
94 }
95 String authType = argument.toUpperCase(Locale.US);
96 if (authType.equals(AUTH_TYPE_PLAIN)) {
97 doPlainAuth(session, initialResponse);
98 return;
99 } else if (authType.equals(AUTH_TYPE_LOGIN)) {
100 doLoginAuth(session, initialResponse);
101 return;
102 } else {
103 doUnknownAuth(session, authType, initialResponse);
104 return;
105 }
106 }
107 }
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123 private void doPlainAuth(SMTPSession session, String initialResponse)
124 throws IOException {
125 String userpass = null, user = null, pass = null, responseString = null;
126 if (initialResponse == null) {
127 responseString = "334 OK. Continue authentication";
128 session.writeResponse(responseString);
129 userpass = session.readCommandLine();
130 } else {
131 userpass = initialResponse.trim();
132 }
133 try {
134 if (userpass != null) {
135 userpass = Base64.decodeAsString(userpass);
136 }
137 if (userpass != null) {
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152 StringTokenizer authTokenizer = new StringTokenizer(userpass, "\0");
153 String authorize_id = authTokenizer.nextToken();
154 user = authTokenizer.nextToken();
155 try {
156 pass = authTokenizer.nextToken();
157 }
158 catch (java.util.NoSuchElementException _) {
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174 pass = user;
175 user = authorize_id;
176 }
177
178 authTokenizer = null;
179 }
180 }
181 catch (Exception e) {
182
183
184 }
185
186 if ((user == null) || (pass == null)) {
187 responseString = "501 Could not decode parameters for AUTH PLAIN";
188 session.writeResponse(responseString);
189 } else if (session.getConfigurationData().getUsersRepository().test(user, pass)) {
190 session.setUser(user);
191 responseString = "235 Authentication Successful";
192 session.writeResponse(responseString);
193 getLogger().info("AUTH method PLAIN succeeded");
194 } else {
195 responseString = "535 Authentication Failed";
196 session.writeResponse(responseString);
197 getLogger().error("AUTH method PLAIN failed");
198 }
199 return;
200 }
201
202
203
204
205
206
207
208 private void doLoginAuth(SMTPSession session, String initialResponse)
209 throws IOException {
210 String user = null, pass = null, responseString = null;
211 if (initialResponse == null) {
212 responseString = "334 VXNlcm5hbWU6";
213 session.writeResponse(responseString);
214 user = session.readCommandLine();
215 } else {
216 user = initialResponse.trim();
217 }
218 if (user != null) {
219 try {
220 user = Base64.decodeAsString(user);
221 } catch (Exception e) {
222
223
224 user = null;
225 }
226 }
227 responseString = "334 UGFzc3dvcmQ6";
228 session.writeResponse(responseString);
229 pass = session.readCommandLine();
230 if (pass != null) {
231 try {
232 pass = Base64.decodeAsString(pass);
233 } catch (Exception e) {
234
235
236 pass = null;
237 }
238 }
239
240 if ((user == null) || (pass == null)) {
241 responseString = "501 Could not decode parameters for AUTH LOGIN";
242 } else if (session.getConfigurationData().getUsersRepository().test(user, pass)) {
243 session.setUser(user);
244 responseString = "235 Authentication Successful";
245 if (getLogger().isDebugEnabled()) {
246
247 getLogger().debug("AUTH method LOGIN succeeded");
248 }
249 } else {
250 responseString = "535 Authentication Failed";
251
252 getLogger().error("AUTH method LOGIN failed");
253 }
254 session.writeResponse(responseString);
255 return;
256 }
257
258
259
260
261
262
263
264
265 private void doUnknownAuth(SMTPSession session, String authType, String initialResponse) {
266 String responseString = "504 Unrecognized Authentication Type";
267 session.writeResponse(responseString);
268 if (getLogger().isErrorEnabled()) {
269 StringBuffer errorBuffer =
270 new StringBuffer(128)
271 .append("AUTH method ")
272 .append(authType)
273 .append(" is an unrecognized authentication type");
274 getLogger().error(errorBuffer.toString());
275 }
276 return;
277 }
278
279
280
281
282
283
284 public Collection getImplCommands() {
285 Collection implCommands = new ArrayList();
286 implCommands.add("AUTH");
287
288 return implCommands;
289 }
290 }