package de.hsadmin.cas;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.Socket;
import java.net.UnknownHostException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;

import org.apache.commons.codec.binary.Base64;
import org.jasig.cas.authentication.handler.AuthenticationException;
import org.jasig.cas.authentication.handler.AuthenticationHandler;
import org.jasig.cas.authentication.principal.Credentials;
import org.jasig.cas.authentication.principal.UsernamePasswordCredentials;

public class SmtpAuthenticator implements AuthenticationHandler {

	private static final int SMTPS_PORT = 465;

	public boolean authenticate(Credentials creds)
			throws AuthenticationException {
		UsernamePasswordCredentials ucreds = (UsernamePasswordCredentials) creds;
		try {
			return isAuthenticated(ucreds.getUsername(), ucreds.getPassword());
		} catch (SmtpAuthException e) {
			return false;
		}
	}

	public boolean supports(Credentials creds) {
		return creds instanceof UsernamePasswordCredentials;
	}

	public boolean isAuthenticated(String user, String passwd)
			throws SmtpAuthException {
		boolean isAuth = false;
		Socket socket = null;
		try {
			SSLContext sc = SSLContext.getInstance("SSLv3");
			sc.init(null, null, null);
			SSLSocketFactory ssf = sc.getSocketFactory();
			if ( user == null || user.length() < 2 || user.length() == 4 ) {
				return false;
			}
			if (user.indexOf('@') > 0) {
				return false;
			}
			try {
				if (user.length() == 2) {
					user = "hsh01-" + user;
				}
				if (user.length() == 3) {
					user = "hsh00-" + user;
				}
				socket = ssf.createSocket(user.substring(0, 5)
						+ ".hostsharing.net", SMTPS_PORT);
			} catch (StringIndexOutOfBoundsException e) {
				return false;
			}
			Writer out = new OutputStreamWriter(socket.getOutputStream(),
					"ISO-8859-1");
			BufferedReader sin = new BufferedReader(new InputStreamReader(
					socket.getInputStream(), "ISO-8859-1"));
			write(out, "EHLO login.hostsharing.net\r\n");
			String answer = read(sin, "220 ");
			answer = read(sin, "250-");
			StringBuffer userPasswd = new StringBuffer();
			userPasswd.append('\000');
			userPasswd.append(user);
			userPasswd.append('\000');
			userPasswd.append(passwd);
			write(out, "AUTH PLAIN "
					+ new String(Base64.encodeBase64(userPasswd.toString().getBytes())) + "\r\n");
			answer = read(sin, "000");
			isAuth = answer.startsWith("235");
			write(out, "QUIT\r\n");
		} catch (NoSuchAlgorithmException e) {
			throw new SmtpAuthException(e.getMessage());
		} catch (KeyManagementException e) {
			throw new SmtpAuthException(e.getMessage());
		} catch (UnknownHostException e) {
			throw new SmtpAuthException(e.getMessage());
		} catch (IOException e) {
			throw new SmtpAuthException(e.getMessage());
		} finally {
			if (socket != null) {
				try {
					socket.close();
				} catch (IOException e) {
				}
			}
		}
		return isAuth;
	}

	private void write(Writer wr, String line) {
		try {
			wr.write(line);
			wr.flush();
		} catch (IOException e) {
		}
	}

	private String read(BufferedReader rd, String returnCode) {
		try {
			String line = rd.readLine();
			while (line != null && line.startsWith(returnCode)) {
				line = rd.readLine();
			}
			return line;
		} catch (IOException e) {
		}
		return "";
	}

	public class SmtpAuthException extends Exception {

		private static final long serialVersionUID = 2394310295147904537L;

		public SmtpAuthException(String message) {
			super(message);
		}
	}

	public static void main(String[] args) {
		SmtpAuthenticator auth = new SmtpAuthenticator();
		try {
			if (auth.isAuthenticated(args[0], args[1])) {
				System.out.println("Login " + args[0] + " Ok");
			} else {
				System.out.println("Falsches Login");
			}
		} catch (SmtpAuthException e) {
			System.out.println(e.getMessage());
		}
	}
}
