/*
* SONEWS News Server
* Copyright (C) 2009-2015 Christian Lins <christian@lins.me>
* Copyright (C) 2011 František Kučera <informace@frantovo.cz>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.sonews.acl;
import java.io.IOException;
import java.util.Arrays;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.sonews.daemon.NNTPConnection;
import org.sonews.daemon.command.Command;
import org.sonews.storage.StorageBackendException;
import org.sonews.storage.StorageManager;
/**
*
* @author František Kučera
*/
public class AuthInfoCommand implements Command {
private static final Logger log = Logger.getLogger(AuthInfoCommand.class
.getName());
private static final String[] SUPPORTED_COMMANDS = { "AUTHINFO" };
@Override
public boolean hasFinished() {
return true;
}
@Override
public String impliedCapability() {
return "AUTHINFO";
}
@Override
public boolean isStateful() {
// TODO: make it statefull?
return false;
}
@Override
public String[] getSupportedCommandStrings() {
return SUPPORTED_COMMANDS;
}
@Override
public void processLine(NNTPConnection conn, String line, byte[] rawLine)
throws IOException, StorageBackendException {
Pattern commandPattern = Pattern.compile("AUTHINFO (USER|PASS) (.*)",
Pattern.CASE_INSENSITIVE);
Matcher commandMatcher = commandPattern.matcher(line);
if (commandMatcher.matches()) {
if (conn.getUser() != null && conn.getUser().isAuthenticated()) {
conn.println("502 Command unavailable (you are already authenticated)");
} else if ("USER".equalsIgnoreCase(commandMatcher.group(1))) {
conn.setUser(new User(commandMatcher.group(2)));
conn.println("381 Password required"); // ask user for his
// password
log.log(Level.FINE,
"User ''{0}'' greets us. We are waiting for his password.",
conn.getUser().getUserName());
} else if ("PASS".equalsIgnoreCase(commandMatcher.group(1))) {
if (conn.getUser() == null) {
conn.println("482 Authentication commands issued out of sequence");
} else {
char[] password = commandMatcher.group(2).toCharArray();
// TODO: StorageManager should return User object instead of
// boolean (so there could be transferred some additional
// information about user)
boolean goodPassword = StorageManager.current()
.authenticateUser(conn.getUser().getUserName(),
password);
Arrays.fill(password, '*');
if (goodPassword) {
conn.println("281 Authentication accepted");
conn.getUser().setAuthenticated(true);
log.log(Level.INFO,
"User ''{0}'' has been succesfully authenticated.",
conn.getUser().getUserName());
} else {
log.log(Level.INFO,
"User ''{0}'' has provided wrong password.",
conn.getUser().getUserName());
conn.setUser(null);
conn.println("481 Authentication failed: wrong password");
}
}
} else {
// impossible, see commandPattern
conn.println("500 Unknown command");
}
} else {
conn.println("500 Unknown command, expecting AUTHINFO USER username or AUTHINFO PASS password ");
}
}
}