From 664136d5631a95f2fe7daca799a73f13be468411 Mon Sep 17 00:00:00 2001 From: Peter Hormanns Date: Wed, 31 Aug 2016 16:53:03 +0200 Subject: [PATCH] better error handling on failed logins --- cli/src/main/java/de/hsadmin/jscli/Main.java | 13 ++- .../main/java/de/hsadmin/jscli/RpcClient.java | 3 +- .../java/de/hsadmin/jscli/ScriptClient.java | 10 +- .../java/de/hsadmin/jscli/TicketProvider.java | 13 +++ .../hsadmin/jscli/cas/CASTicketProvider.java | 98 +++++++++---------- .../hsadmin/jscli/cas/TestTicketProvider.java | 28 ++++++ .../jscli/cas/TicketProviderFactory.java | 25 +++++ .../hsadmin/jscli/console/PasswordReader.java | 4 +- 8 files changed, 131 insertions(+), 63 deletions(-) create mode 100644 cli/src/main/java/de/hsadmin/jscli/TicketProvider.java create mode 100644 cli/src/main/java/de/hsadmin/jscli/cas/TestTicketProvider.java create mode 100644 cli/src/main/java/de/hsadmin/jscli/cas/TicketProviderFactory.java diff --git a/cli/src/main/java/de/hsadmin/jscli/Main.java b/cli/src/main/java/de/hsadmin/jscli/Main.java index d9a4840..bb4a82c 100644 --- a/cli/src/main/java/de/hsadmin/jscli/Main.java +++ b/cli/src/main/java/de/hsadmin/jscli/Main.java @@ -7,6 +7,7 @@ import java.io.InputStreamReader; import de.hsadmin.jscli.conf.CommandlineParser; import de.hsadmin.jscli.console.ConsoleWrapper; +import de.hsadmin.jscli.exception.JSCliException; import de.hsadmin.jscli.json.JSONFormatter; @@ -65,8 +66,8 @@ public class Main { try { scriptClient.execute(command); console.println(formatter.format(scriptClient.getLastRpcResult())); - } catch (Exception e) { - console.println("Error: " + e.getLocalizedMessage() + "\n"); + } catch (JSCliException e) { + console.println(findRootException(e) + "\n"); } command = console.readInput(); } @@ -77,4 +78,12 @@ public class Main { } } + private static String findRootException(final Exception exp) { + Throwable cause = exp; + while (cause.getCause() != null && cause.getCause() != cause) { + cause = cause.getCause(); + } + return "Error: " + cause.getLocalizedMessage(); + } + } diff --git a/cli/src/main/java/de/hsadmin/jscli/RpcClient.java b/cli/src/main/java/de/hsadmin/jscli/RpcClient.java index b193b54..153e139 100644 --- a/cli/src/main/java/de/hsadmin/jscli/RpcClient.java +++ b/cli/src/main/java/de/hsadmin/jscli/RpcClient.java @@ -11,7 +11,6 @@ import org.apache.xmlrpc.XmlRpcException; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; -import de.hsadmin.jscli.cas.CASTicketProvider; import de.hsadmin.jscli.conf.Config; import de.hsadmin.jscli.exception.JSCliException; @@ -22,7 +21,7 @@ public class RpcClient { private final List clientList; private final Map clientMap; - public RpcClient(final CASTicketProvider tgt) throws JSCliException { + public RpcClient() throws JSCliException { clientList = new ArrayList(); clientMap = new HashMap(); try { diff --git a/cli/src/main/java/de/hsadmin/jscli/ScriptClient.java b/cli/src/main/java/de/hsadmin/jscli/ScriptClient.java index b4c7870..0324884 100644 --- a/cli/src/main/java/de/hsadmin/jscli/ScriptClient.java +++ b/cli/src/main/java/de/hsadmin/jscli/ScriptClient.java @@ -11,7 +11,7 @@ import javax.script.ScriptEngine; import javax.script.ScriptEngineManager; import javax.script.ScriptException; -import de.hsadmin.jscli.cas.CASTicketProvider; +import de.hsadmin.jscli.cas.TicketProviderFactory; import de.hsadmin.jscli.console.ConsoleWrapper; import de.hsadmin.jscli.exception.JSCliException; @@ -21,11 +21,9 @@ public class ScriptClient { final private Set completionStrings; public ScriptClient(final ConsoleWrapper console, final String user, final String runAs, final String... arguments) throws JSCliException { - final CASTicketProvider ticketProvider = new CASTicketProvider(console, user, runAs); - final RpcClient rpcClient = new RpcClient(ticketProvider); - final ScriptEngineManager engineManager = new ScriptEngineManager(); - engine = engineManager.getEngineByName("js"); - engine.put("casgrantingticket", ticketProvider); + final RpcClient rpcClient = new RpcClient(); + engine = new ScriptEngineManager().getEngineByName("js"); + engine.put("casgrantingticket", TicketProviderFactory.getInstance(console, user, runAs)); engine.put("xmlrpcclient", rpcClient); engine.put("xmlrpcLastResult", null); completionStrings = new HashSet(); diff --git a/cli/src/main/java/de/hsadmin/jscli/TicketProvider.java b/cli/src/main/java/de/hsadmin/jscli/TicketProvider.java new file mode 100644 index 0000000..6e50c0c --- /dev/null +++ b/cli/src/main/java/de/hsadmin/jscli/TicketProvider.java @@ -0,0 +1,13 @@ +package de.hsadmin.jscli; + +import java.io.FileNotFoundException; + +import de.hsadmin.jscli.exception.JSCliException; + +public interface TicketProvider { + + public String getTicket() throws JSCliException, FileNotFoundException; + + public String getRunAs(); + +} \ No newline at end of file diff --git a/cli/src/main/java/de/hsadmin/jscli/cas/CASTicketProvider.java b/cli/src/main/java/de/hsadmin/jscli/cas/CASTicketProvider.java index c17cf17..9d1ce91 100644 --- a/cli/src/main/java/de/hsadmin/jscli/cas/CASTicketProvider.java +++ b/cli/src/main/java/de/hsadmin/jscli/cas/CASTicketProvider.java @@ -18,14 +18,12 @@ import java.util.Properties; import javax.net.ssl.HttpsURLConnection; +import de.hsadmin.jscli.TicketProvider; import de.hsadmin.jscli.conf.Config; import de.hsadmin.jscli.console.PasswordReader; import de.hsadmin.jscli.exception.JSCliException; -public class CASTicketProvider { - - private static final String LOGIN_URL = "https://login.hostsharing.net:443/cas/v1/tickets"; - private static final String BACKEND_URL = "https://config.hostsharing.net:443/hsar/backend"; +public class CASTicketProvider implements TicketProvider { final private String loginURL; final private String backendURL; @@ -35,13 +33,12 @@ public class CASTicketProvider { private String grantingTicket; - public CASTicketProvider(final PasswordReader console, final String user, final String runAs) throws JSCliException { + public CASTicketProvider(final PasswordReader console, final String user, final String runAs, final String backendURL, final String loginURL) throws JSCliException { this.passwordReader = console; this.user = user; this.runAs = runAs; - final Config config = Config.getInstance(); - backendURL = config.getProperty("backendURL", BACKEND_URL); - loginURL = config.getProperty("loginURL", LOGIN_URL); + this.backendURL = backendURL; + this.loginURL = loginURL; if ("TestUmgebung".equals(loginURL)) { grantingTicket = "ticket:" + user; } else { @@ -49,19 +46,39 @@ public class CASTicketProvider { } } + @Override public String getTicket() throws JSCliException, FileNotFoundException { - if (grantingTicket != null && grantingTicket.startsWith("ticket:")) { - return grantingTicket.replaceFirst("ticket", "user"); - } try { - String encodedParams = URLEncoder.encode("service", "UTF-8") - + "=" + URLEncoder.encode(backendURL, "UTF-8"); - return doHttpPost(grantingTicket, encodedParams); + final String encodedParams = + URLEncoder.encode("service", "UTF-8") + "=" + URLEncoder.encode(backendURL, "UTF-8"); + String urlString = grantingTicket; + String result = null; + boolean grantingTicketIsValid = false; + int trails = 0; + while (!grantingTicketIsValid) { + try { + result = requestForServiceTicket(urlString, encodedParams); + grantingTicketIsValid = true; + grantingTicket = urlString; + saveProperties(grantingTicket, getTicketFile()); + } catch (IOException e) { + if (trails > 0) { + passwordReader.println("login failed"); + } + trails++; + if (trails > 3) { + throw new JSCliException("exceeded number of login attempts"); + } + urlString = getGrantingTicket(); + } + } + return result; } catch (UnsupportedEncodingException e) { throw new JSCliException(e); } } + @Override public String getRunAs() { return runAs; } @@ -77,7 +94,7 @@ public class CASTicketProvider { + "=" + URLEncoder.encode(user, "UTF-8") + "&" + URLEncoder.encode("password", "UTF-8") + "=" + URLEncoder.encode(password, "UTF-8"); - grantingTicket = doHttpPost(loginURL, encodedParams); + grantingTicket = requestForGrantingTicket(loginURL, encodedParams); } catch (UnsupportedEncodingException e) { throw new JSCliException(e); } catch (FileNotFoundException e) { @@ -90,47 +107,30 @@ public class CASTicketProvider { return passwordReader.readPassword(); } - private String doHttpPost(final String urlString, final String encodedParams) throws JSCliException, FileNotFoundException { - String result = null; + private String requestForGrantingTicket(final String urlString, final String encodedParams) throws JSCliException, FileNotFoundException { try { - result = extractTicket(urlString, encodedParams); - } catch (FileNotFoundException e) { - grantingTicket = getGrantingTicket(); - saveProperties(grantingTicket, getTicketFile()); - try { - result = extractTicket(grantingTicket, encodedParams); - } catch (IOException e1) { - throw new JSCliException(e1); - } + final HttpsURLConnection connection = doConnect(urlString, encodedParams); + return connection.getHeaderField("Location"); } catch (IOException e) { throw new JSCliException(e); } - return result; } - private String extractTicket(final String urlString, - final String encodedParams) throws MalformedURLException, - IOException, ProtocolException { - String result; + private String requestForServiceTicket(final String urlString, final String encodedParams) + throws MalformedURLException, IOException, ProtocolException + { final HttpsURLConnection connection = doConnect(urlString, encodedParams); - final String ticket = readTicket(connection); - if (ticket != null && ticket.startsWith("ST-")) { - result = ticket; - } else { - result = connection.getHeaderField("Location"); - } - return result; - } - - private String readTicket(final HttpsURLConnection connection) - throws IOException { - final BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream())); + final InputStreamReader inputStreamReader = new InputStreamReader(connection.getInputStream()); + final BufferedReader reader = new BufferedReader(inputStreamReader); final String ticket = reader.readLine(); String readLine = null; do { readLine = reader.readLine(); } while (readLine != null); - return ticket; + if (ticket != null && ticket.startsWith("ST-")) { + return ticket; + } + return null; } private HttpsURLConnection doConnect(final String urlString, @@ -151,15 +151,9 @@ public class CASTicketProvider { } private String readFiledGrantingTicket() throws JSCliException { - String filedTicket = null; final File file = getTicketFile(); final Properties properties = loadProperties(file); - filedTicket = properties.getProperty(user); - if (filedTicket == null) { - filedTicket = getGrantingTicket(); - saveProperties(filedTicket, file); - } - return filedTicket; + return properties.getProperty(user); } private File getTicketFile() { @@ -173,7 +167,7 @@ public class CASTicketProvider { if (filedTicket != null) { properties.setProperty(user, filedTicket); try { - properties.store(new FileOutputStream(file), ""); + properties.store(new FileOutputStream(file), "stored cas tickets"); } catch (IOException e) { throw new JSCliException(e); } diff --git a/cli/src/main/java/de/hsadmin/jscli/cas/TestTicketProvider.java b/cli/src/main/java/de/hsadmin/jscli/cas/TestTicketProvider.java new file mode 100644 index 0000000..3bb3f67 --- /dev/null +++ b/cli/src/main/java/de/hsadmin/jscli/cas/TestTicketProvider.java @@ -0,0 +1,28 @@ +package de.hsadmin.jscli.cas; + +import java.io.FileNotFoundException; + +import de.hsadmin.jscli.TicketProvider; +import de.hsadmin.jscli.exception.JSCliException; + +public class TestTicketProvider implements TicketProvider { + + private final String grantingTicket; + private final String runAs; + + public TestTicketProvider(final String user, final String runAs) { + this.grantingTicket = "user:" + user; + this.runAs = runAs; + } + + @Override + public String getTicket() throws JSCliException, FileNotFoundException { + return grantingTicket; + } + + @Override + public String getRunAs() { + return runAs; + } + +} diff --git a/cli/src/main/java/de/hsadmin/jscli/cas/TicketProviderFactory.java b/cli/src/main/java/de/hsadmin/jscli/cas/TicketProviderFactory.java new file mode 100644 index 0000000..47691ce --- /dev/null +++ b/cli/src/main/java/de/hsadmin/jscli/cas/TicketProviderFactory.java @@ -0,0 +1,25 @@ +package de.hsadmin.jscli.cas; + +import de.hsadmin.jscli.TicketProvider; +import de.hsadmin.jscli.conf.Config; +import de.hsadmin.jscli.console.PasswordReader; +import de.hsadmin.jscli.exception.JSCliException; + +public class TicketProviderFactory { + + private static final String HOSTSHARING_LOGIN_URL = "https://login.hostsharing.net:443/cas/v1/tickets"; + private static final String HOSTSHARING_BACKEND_URL = "https://config.hostsharing.net:443/hsar/backend"; + + public static TicketProvider getInstance(final PasswordReader console, final String user, final String runAs) throws JSCliException + { + final Config config = Config.getInstance(); + final String backendURL = config.getProperty("backendURL", HOSTSHARING_BACKEND_URL); + final String loginURL = config.getProperty("loginURL", HOSTSHARING_LOGIN_URL); + if ("TestUmgebung".equalsIgnoreCase(loginURL)) { + return new TestTicketProvider(user, runAs); + } else { + return new CASTicketProvider(console, user, runAs, backendURL, loginURL); + } + } + +} diff --git a/cli/src/main/java/de/hsadmin/jscli/console/PasswordReader.java b/cli/src/main/java/de/hsadmin/jscli/console/PasswordReader.java index 4a42f3c..95f220d 100644 --- a/cli/src/main/java/de/hsadmin/jscli/console/PasswordReader.java +++ b/cli/src/main/java/de/hsadmin/jscli/console/PasswordReader.java @@ -4,6 +4,8 @@ import de.hsadmin.jscli.exception.JSCliException; public interface PasswordReader { - String readPassword() throws JSCliException; + public String readPassword() throws JSCliException; + + public void println(final String text) throws JSCliException; }