From: Fredrik Tolf Date: Mon, 28 Jan 2008 03:07:13 +0000 (+0100) Subject: Java: Added a session handler with authentication capability. X-Git-Url: http://git.dolda2000.com/gitweb/?p=doldaconnect.git;a=commitdiff_plain;h=7131093cf84874bc7290c18cf34a3ae4d36cf2bd Java: Added a session handler with authentication capability. --- diff --git a/lib/java/dolda/dolcon/AuthException.java b/lib/java/dolda/dolcon/AuthException.java new file mode 100644 index 0000000..6145955 --- /dev/null +++ b/lib/java/dolda/dolcon/AuthException.java @@ -0,0 +1,11 @@ +package dolda.dolcon; + +public class AuthException extends Exception { + public AuthException(String msg) { + super(msg); + } + + public AuthException(String msg, Throwable cause) { + super(msg, cause); + } +} diff --git a/lib/java/dolda/dolcon/Authenticator.java b/lib/java/dolda/dolcon/Authenticator.java new file mode 100644 index 0000000..b9e9cfe --- /dev/null +++ b/lib/java/dolda/dolcon/Authenticator.java @@ -0,0 +1,10 @@ +package dolda.dolcon; + +import dolda.dolcon.protocol.Command; +import dolda.dolcon.protocol.Response; +import java.util.List; + +public interface Authenticator { + public String handles(List name); + public Command step(Response resp) throws AuthException, ProtocolException, InterruptedException; +} diff --git a/lib/java/dolda/dolcon/InteractiveAuth.java b/lib/java/dolda/dolcon/InteractiveAuth.java new file mode 100644 index 0000000..0da9f2a --- /dev/null +++ b/lib/java/dolda/dolcon/InteractiveAuth.java @@ -0,0 +1,34 @@ +package dolda.dolcon; + +import java.util.List; +import dolda.dolcon.protocol.Response; +import dolda.dolcon.protocol.Command; + +public abstract class InteractiveAuth implements Authenticator { + public String handles(List name) { + if(name.contains("pam")) + return("pam"); + return(null); + } + + public Command step(Response resp) throws AuthException, ProtocolException, InterruptedException { + if(resp.code == 301) { + return(new Command("pass", promptnoecho(resp.token(0, 0)))); + } else if(resp.code == 302) { + return(new Command("pass", promptecho(resp.token(0, 0)))); + } else if(resp.code == 303) { + info(resp.token(0, 0)); + return(new Command("pass", "")); + } else if(resp.code == 304) { + error(resp.token(0, 0)); + return(new Command("pass", "")); + } else { + throw(new ResponseException(resp, 0)); + } + } + + public abstract String promptecho(String msg) throws AuthException; + public abstract String promptnoecho(String msg) throws AuthException; + public abstract void info(String msg) throws AuthException; + public abstract void error(String msg) throws AuthException; +} diff --git a/lib/java/dolda/dolcon/NoMechException.java b/lib/java/dolda/dolcon/NoMechException.java new file mode 100644 index 0000000..527ffbc --- /dev/null +++ b/lib/java/dolda/dolcon/NoMechException.java @@ -0,0 +1,7 @@ +package dolda.dolcon; + +public class NoMechException extends AuthException { + public NoMechException() { + super("No supported authentication mechanism was offered by the server"); + } +} diff --git a/lib/java/dolda/dolcon/PasswordAuth.java b/lib/java/dolda/dolcon/PasswordAuth.java new file mode 100644 index 0000000..9f62d7a --- /dev/null +++ b/lib/java/dolda/dolcon/PasswordAuth.java @@ -0,0 +1,32 @@ +package dolda.dolcon; + +import java.util.List; +import dolda.dolcon.protocol.Response; +import dolda.dolcon.protocol.Command; + +public class PasswordAuth implements Authenticator { + private String password; + + public PasswordAuth(String password) { + this.password = password; + } + + public String handles(List name) { + System.out.println(name); + if(name.contains("pam")) + return("pam"); + return(null); + } + + public Command step(Response resp) throws ProtocolException { + if((password != null) && (resp.code == 301)) { + try { + return(new Command("pass", password)); + } finally { + password = null; + } + } else { + throw(new ResponseException(resp, 0)); + } + } +} diff --git a/lib/java/dolda/dolcon/ProtocolException.java b/lib/java/dolda/dolcon/ProtocolException.java new file mode 100644 index 0000000..474bea1 --- /dev/null +++ b/lib/java/dolda/dolcon/ProtocolException.java @@ -0,0 +1,16 @@ +package dolda.dolcon; + +/** + * The purpose of this exception is to wrap together all the low-level + * protocol exceptions, that the programmer is unlikely to want to + * differentiate between. + */ +public class ProtocolException extends Exception { + public ProtocolException(String msg) { + super(msg); + } + + public ProtocolException(Exception cause) { + super("Unhandled DC protocol condition", cause); + } +} diff --git a/lib/java/dolda/dolcon/ResponseException.java b/lib/java/dolda/dolcon/ResponseException.java new file mode 100644 index 0000000..d218b8e --- /dev/null +++ b/lib/java/dolda/dolcon/ResponseException.java @@ -0,0 +1,26 @@ +package dolda.dolcon; + +import dolda.dolcon.protocol.Response; + +public class ResponseException extends ProtocolException { + Response resp; + int expected; + + public ResponseException(Response resp, int expected) { + super("Unhandled DC protocol response (" + resp.code + " != " + expected + ")"); + this.resp = resp; + this.expected = expected; + } + + public ResponseException(String msg, Response resp, int expected) { + super(msg); + this.resp = resp; + this.expected = expected; + } + + public static Response check(Response resp, int expect) throws ResponseException { + if(resp.code != expect) + throw(new ResponseException(resp, expect)); + return(resp); + } +} diff --git a/lib/java/dolda/dolcon/Session.java b/lib/java/dolda/dolcon/Session.java new file mode 100644 index 0000000..0ef49d6 --- /dev/null +++ b/lib/java/dolda/dolcon/Session.java @@ -0,0 +1,60 @@ +package dolda.dolcon; + +import java.util.*; +import dolda.dolcon.protocol.*; + +public class Session { + private Connection conn; + + public Session(String aspec, String username, List auth) throws AuthException, ProtocolException, InterruptedException { + conn = new Connection(aspec); + conn.expectVersion(2); + try { + conn.syncConnect(); + } catch(ConnectException e) { + throw(new ProtocolException(e)); + } + authenticate(username, auth); + } + + public Session(String aspec, String username, Authenticator... auth) throws AuthException, ProtocolException, InterruptedException { + this(aspec, username, Arrays.asList(auth)); + } + + private void authenticate(String username, List auth) throws AuthException, ProtocolException, InterruptedException { + Response resp; + + try { + resp = ResponseException.check(conn.ecmd("lsauth"), 200); + List mechs = new LinkedList(); + for(List mech : resp.lines) + mechs.add(mech.get(0).intern()); + String use = null; + Authenticator au = null; + for(Authenticator a : auth) { + System.out.println(a); + use = a.handles(mechs); + if(use != null) { + au = a; + break; + } + } + if(use == null) + throw(new NoMechException()); + resp = conn.ecmd("login", use, username); + while(true) { + if(resp.code == 200) { + return; + } else if((resp.code / 100) == 3) { + resp = conn.ecmd(au.step(resp)); + } else if((resp.code / 100) == 5) { + throw(new AuthException(resp.token(0, 0))); + } else { + throw(new ResponseException(resp, 0)); + } + } + } catch(ClosedException e) { + throw(new ProtocolException(e)); + } + } +} diff --git a/lib/java/dolda/dolcon/protocol/Connection.java b/lib/java/dolda/dolcon/protocol/Connection.java index 43cf5a3..54aea90 100644 --- a/lib/java/dolda/dolcon/protocol/Connection.java +++ b/lib/java/dolda/dolcon/protocol/Connection.java @@ -381,7 +381,6 @@ public class Connection { code = Integer.parseInt(ct.toString()); ct.setLength(0); state = "start"; - continue eat; } else { ct.append(c); } diff --git a/lib/java/dolda/dolcon/protocol/Response.java b/lib/java/dolda/dolcon/protocol/Response.java index 990ef2b..9a4e74f 100644 --- a/lib/java/dolda/dolcon/protocol/Response.java +++ b/lib/java/dolda/dolcon/protocol/Response.java @@ -3,9 +3,9 @@ package dolda.dolcon.protocol; import java.util.*; public class Response { - List> lines; - Command cmd; - int code; + public List> lines; + public Command cmd; + public int code; public Response(int code, List> lines) { this.code = code; @@ -19,4 +19,8 @@ public class Response { public String token(int line, int token) { return(lines.get(line).get(token)); } + + public List line(int line) { + return(lines.get(line)); + } }