diff --git a/api/src/main/java/io/github/wulkanowy/api/Client.java b/api/src/main/java/io/github/wulkanowy/api/Client.java index c3693c40..b5080e0c 100644 --- a/api/src/main/java/io/github/wulkanowy/api/Client.java +++ b/api/src/main/java/io/github/wulkanowy/api/Client.java @@ -23,7 +23,7 @@ public class Client { private String symbol; - private Date lastSuccessRequest = null; + private Date lastSuccessRequest; private Cookies cookies = new Cookies(); @@ -103,7 +103,7 @@ public class Client { return getPageByUrl(url, loginBefore, null); } - public Document getPageByUrl(String url, boolean loginBefore, Map cookies) throws IOException, VulcanException { + public synchronized Document getPageByUrl(String url, boolean loginBefore, Map cookies) throws IOException, VulcanException { if (loginBefore) { login(); } @@ -128,7 +128,7 @@ public class Client { return doc; } - public Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { + public synchronized Document postPageByUrl(String url, String[][] params) throws IOException, VulcanException { Connection connection = Jsoup.connect(getFilledUrl(url)); for (String[] data : params) { diff --git a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java index fbc14486..1acecfd3 100644 --- a/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java +++ b/api/src/main/java/io/github/wulkanowy/api/StudentAndParent.java @@ -106,7 +106,11 @@ public class StudentAndParent implements SnP { Document doc = client.getPageByUrl(getBaseUrl() + url, true, cookies); - if ("Witryna ucznia i rodzica – Strona główna".equals(doc.select("title").first().text())) { + if (!doc.title().startsWith("Witryna ucznia i rodzica")) { + throw new VulcanException("Expected SnP page, got page with title: " + doc.title()); + } + + if (doc.title().endsWith("Strona główna")) { throw new VulcanException("Sesja została nieprawidłowo zainicjowana"); } diff --git a/api/src/main/java/io/github/wulkanowy/api/login/Login.java b/api/src/main/java/io/github/wulkanowy/api/login/Login.java index 32e372c1..b8b52438 100644 --- a/api/src/main/java/io/github/wulkanowy/api/login/Login.java +++ b/api/src/main/java/io/github/wulkanowy/api/login/Login.java @@ -13,7 +13,7 @@ import io.github.wulkanowy.api.VulcanException; public class Login { - private static final String LOGIN_PAGE_URL = "{schema}://cufs.{host}/{symbol}/Account/LogOn" + + static final String LOGIN_PAGE_URL = "{schema}://cufs.{host}/{symbol}/Account/LogOn" + "?ReturnUrl=%2F{symbol}%2FFS%2FLS%3Fwa%3Dwsignin1.0%26wtrealm%3D" + "{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx%26wctx%3D" + "{schema}%253a%252f%252fuonetplus.{host}%252f{symbol}%252fLoginEndpoint.aspx"; @@ -47,6 +47,8 @@ public class Login { ); credentials = getFormStateParams(formSecond, email, password); nextUrl = formSecond.select("#form1").first().attr("abs:action"); + } else if (!"Logowanie".equals(loginPage.select("#h1Default").text())) { + throw new VulcanException("Expected login page, got page with title: " + loginPage.title()); } Document html = client.postPageByUrl(nextUrl, credentials); @@ -77,14 +79,17 @@ public class Login { String sendCertificate(Document doc, String defaultSymbol) throws IOException, VulcanException { String certificate = doc.select("input[name=wresult]").val(); - String symbol = findSymbol(defaultSymbol, certificate); - client.setSymbol(symbol); + if ("".equals(certificate)) { + throw new VulcanException("Expected certificate, got empty string. Page title: " + doc.title()); + } + + client.setSymbol(findSymbol(defaultSymbol, certificate)); Document targetDoc = sendCertData(doc); - String title = targetDoc.select("title").text(); + String title = targetDoc.title(); if ("Working...".equals(title)) { // on adfs login - title = sendCertData(targetDoc).select("title").text(); + title = sendCertData(targetDoc).title(); } if ("Logowanie".equals(title)) { @@ -95,12 +100,16 @@ public class Login { throw new LoginErrorException("Expected page title `UONET+`, got " + title); } - return symbol; + return client.getSymbol(); } private Document sendCertData(Document doc) throws IOException, VulcanException { String url = doc.select("form[name=hiddenform]").attr("action"); + if (!doc.title().equals("Working...")) { + throw new VulcanException("Expected certificate page, got page with title: " + doc.title()); + } + return client.postPageByUrl(url.replaceFirst("Default", "{symbol}"), new String[][]{ {"wa", "wsignin1.0"}, {"wresult", doc.select("input[name=wresult]").val()}, @@ -108,7 +117,7 @@ public class Login { }); } - private String findSymbol(String symbol, String certificate) { + private String findSymbol(String symbol, String certificate) throws AccountPermissionException { if ("Default".equals(symbol)) { return findSymbolInCertificate(certificate); } @@ -116,13 +125,13 @@ public class Login { return symbol; } - String findSymbolInCertificate(String certificate) { + String findSymbolInCertificate(String certificate) throws AccountPermissionException { Elements instances = Jsoup .parse(certificate.replaceAll(":", ""), "", Parser.xmlParser()) .select("[AttributeName=\"UserInstance\"] samlAttributeValue"); - if (instances.isEmpty()) { - return ""; + if (instances.size() < 2) { // 1st index is always `Default` + throw new AccountPermissionException("First login detected, specify symbol"); } return instances.get(1).text(); diff --git a/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java b/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java index 01602ebe..4a4f8915 100644 --- a/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java +++ b/api/src/test/java/io/github/wulkanowy/api/login/LoginTest.java @@ -34,6 +34,10 @@ public class LoginTest { Client client = getClient("Logowanie-success.html"); Mockito.when(client.getPageByUrl(Mockito.anyString(), Mockito.anyBoolean())) .thenReturn(getFixtureAsDocument("Logowanie-error.html")); + Mockito.when(client.postPageByUrl(Mockito.eq(Login.LOGIN_PAGE_URL), Mockito.any(String[][].class))) + .thenReturn(getFixtureAsDocument("Logowanie-certyfikat.html")); + Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString()); + Mockito.when(client.getSymbol()).thenCallRealMethod(); Login login = new Login(client); Assert.assertEquals("d123", login.login("a@a", "pswd", "d123")); @@ -57,22 +61,31 @@ public class LoginTest { Login login = new Login(client); Assert.assertEquals( - getFixtureAsString("cert-stock.xml").replaceAll("\\s+",""), - login.sendCredentials("a@a", "passwd").select("input[name=wresult]").attr("value").replaceAll("\\s+","") + getFixtureAsString("cert-stock.xml").replaceAll("\\s+", ""), + login.sendCredentials("a@a", "passwd") + .select("input[name=wresult]") + .attr("value") + .replaceAll("\\s+", "") ); } @Test public void sendCertificateNotDefaultSymbolSuccessTest() throws Exception { - Login login = new Login(getClient("Logowanie-success.html")); + Client client = getClient("Logowanie-success.html"); + Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString()); + Mockito.when(client.getSymbol()).thenCallRealMethod(); + Login login = new Login(client); - Assert.assertEquals("wulkanowyschool321", - login.sendCertificate(new Document(""), "wulkanowyschool321")); + Assert.assertEquals("wulkanowyschool321", login.sendCertificate( + getFixtureAsDocument("Logowanie-certyfikat.html"), "wulkanowyschool321")); } @Test public void sendCertificateDefaultSymbolSuccessTest() throws Exception { - Login login = new Login(getClient("Logowanie-success.html")); + Client client = getClient("Logowanie-success.html"); + Mockito.doCallRealMethod().when(client).setSymbol(Mockito.anyString()); + Mockito.when(client.getSymbol()).thenCallRealMethod(); + Login login = new Login(client); Assert.assertEquals("demo12345", login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "Default")); @@ -80,16 +93,18 @@ public class LoginTest { @Test(expected = AccountPermissionException.class) public void sendCertificateAccountPermissionTest() throws Exception { - Login login = new Login(getClient("Logowanie-brak-dostepu.html")); + Client client = getClient("Logowanie-brak-dostepu.html"); - login.sendCertificate(getFixtureAsDocument("cert-stock.xml"), "demo123"); + Login login = new Login(client); + + login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "demo123"); } @Test(expected = LoginErrorException.class) public void sendCertificateLoginErrorTest() throws Exception { Login login = new Login(getClient("Logowanie-certyfikat.html")); // change to other document - login.sendCertificate(getFixtureAsDocument("cert-stock.xml"), "demo123"); + login.sendCertificate(getFixtureAsDocument("Logowanie-certyfikat.html"), "demo123"); } @Test @@ -101,10 +116,10 @@ public class LoginTest { Assert.assertEquals("demo12345", login.findSymbolInCertificate(certificate)); } - @Test - public void findSymbolInInvalidCertificateTest() throws Exception { + @Test(expected = AccountPermissionException.class) + public void findSymbolInCertificateWithoutSecondInstanceTest() throws Exception { Login login = new Login(getClient("Logowanie-certyfikat.html")); - Assert.assertEquals("", login.findSymbolInCertificate("")); // change to real cert with empty symbols + login.findSymbolInCertificate(getFixtureAsString("cert-no-symbols.xml")); } } diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html index 08713188..afb044d7 100644 --- a/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html +++ b/api/src/test/resources/io/github/wulkanowy/api/login/Logowanie-error.html @@ -6,6 +6,9 @@
+
+

Logowanie

+
Zła nazwa użytkownika lub hasło
diff --git a/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml b/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml new file mode 100644 index 00000000..ca14bdf5 --- /dev/null +++ b/api/src/test/resources/io/github/wulkanowy/api/login/cert-no-symbols.xml @@ -0,0 +1,13 @@ + + + + + + + Default + + + + + + diff --git a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java index 26ec36dd..a430e335 100644 --- a/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java +++ b/app/src/main/java/io/github/wulkanowy/data/db/resources/ResourcesRepository.java @@ -52,7 +52,7 @@ public class ResourcesRepository implements ResourcesContract { } else if (exception instanceof SocketTimeoutException) { return resources.getString(R.string.generic_timeout_error); } else if (exception instanceof NotLoggedInErrorException || exception instanceof IOException) { - return resources.getString(R.string.login_denied_text); + return resources.getString(R.string.login_failed_text); } else { return exception.getMessage(); } diff --git a/app/src/main/res/values-pl/strings.xml b/app/src/main/res/values-pl/strings.xml index 38169d81..aeb828d1 100644 --- a/app/src/main/res/values-pl/strings.xml +++ b/app/src/main/res/values-pl/strings.xml @@ -19,7 +19,7 @@ Pomyślnie zalogowano Niepoprawny e-mail lub hasło Brak uprawnień do otwarcia dziennika. Sprawdź wprowadzoną nazwę powiatu - Logowanie nie powiodło się. Spróbuj zrestartować aplikację + Logowanie nie powiodło się. Spróbuj ponownie lub zrestartuj aplikację Nie masz jeszcze konta? Załóż je Zapomniałeś hasła? diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 2130120e..1ffea541 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -19,7 +19,7 @@ Login is successful Bad e-mail or password No permission to open log. Check entered symbol - Login is failed. Try restart the app + Login is failed. Try again or restart the app No account yet? Create one Forgot password?