diff --git a/app/src/main/java/de/sebse/fuplanner/services/fulogin/UserLoginResult.java b/app/src/main/java/de/sebse/fuplanner/services/fulogin/UserLoginResult.java new file mode 100644 index 0000000..ce7c5c0 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/fulogin/UserLoginResult.java @@ -0,0 +1,4 @@ +package de.sebse.fuplanner.services.fulogin; + +public class UserLoginResult { +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/Constants.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/Constants.java index 5929ffd..6cadd78 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/Constants.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/Constants.java @@ -1,5 +1,6 @@ package de.sebse.fuplanner.services.kvv; public class Constants { - public static final String KVV_SERVER_URL = "https://mycampus.imp.fu-berlin.de/"; + public static final String WB_SERVER_URL = "https://mycampus.imp.fu-berlin.de/"; + public static final String BB_SERVER_URL = "https://lms.fu-berlin.de/"; } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/KVV.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/KVV.java index a954bdc..00213d0 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/KVV.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/KVV.java @@ -13,7 +13,7 @@ import org.jetbrains.annotations.NotNull; import java.util.HashMap; import de.sebse.fuplanner.services.kvv.types.LoginTokenBB; -import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; +import de.sebse.fuplanner.services.kvv.types.LoginTokenWB; import de.sebse.fuplanner.tools.CustomAccountManager; public class KVV extends Service { @@ -36,7 +36,7 @@ public class KVV extends Service { } @Override - public void onLogin(LoginTokenKVV tokenKVV, LoginTokenBB tokenBB, boolean isOnlyRefresh) { + public void onLogin(LoginTokenWB tokenKVV, LoginTokenBB tokenBB, boolean isOnlyRefresh) { for (KVVListener listener : mListeners.values()) listener.onLogin(tokenKVV, tokenBB, isOnlyRefresh); } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java index dbb6b9c..3f3793f 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/KVVListener.java @@ -3,12 +3,12 @@ package de.sebse.fuplanner.services.kvv; import com.android.volley.NetworkResponse; import de.sebse.fuplanner.services.kvv.types.LoginTokenBB; -import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; +import de.sebse.fuplanner.services.kvv.types.LoginTokenWB; import de.sebse.fuplanner.services.kvv.types.Modules; import de.sebse.fuplanner.tools.CustomAccountManager; public interface KVVListener { - default void onLogin(LoginTokenKVV tokenKVV, LoginTokenBB tokenBB, boolean isOnlyRefresh) {} + default void onLogin(LoginTokenWB tokenKVV, LoginTokenBB tokenBB, boolean isOnlyRefresh) {} default void onLogout() {} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java index 9985b07..a344a22 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/Login.java @@ -10,9 +10,9 @@ import de.sebse.fuplanner.R; import de.sebse.fuplanner.services.fulogin.AccountGeneral; import de.sebse.fuplanner.services.kvv.sync.BBLogin; import de.sebse.fuplanner.services.kvv.sync.FULogin; -import de.sebse.fuplanner.services.kvv.sync.KVVLogin; +import de.sebse.fuplanner.services.kvv.sync.WBLogin; import de.sebse.fuplanner.services.kvv.types.LoginTokenBB; -import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; +import de.sebse.fuplanner.services.kvv.types.LoginTokenWB; import de.sebse.fuplanner.tools.CustomAccountManager; import de.sebse.fuplanner.tools.NetworkCallbackCollector; import de.sebse.fuplanner.tools.Preferences; @@ -31,10 +31,10 @@ public class Login { private final KVVListener mListener; private Context context; - @Nullable private LoginTokenKVV mTokenKVV; + @Nullable private LoginTokenWB mTokenKVV; @Nullable private LoginTokenBB mTokenBB; private boolean mLoginPending = false; - private final NetworkCallbackCollector> mRefreshCallbacks = new NetworkCallbackCollector<>(); + private final NetworkCallbackCollector> mRefreshCallbacks = new NetworkCallbackCollector<>(); private final NetworkCallbackCollector mRestoreCallbacks = new NetworkCallbackCollector<>(); Login(KVVListener listener, Context context) { @@ -53,7 +53,7 @@ public class Login { return; } mLoginPending = true; - LoginTokenKVV.load(mListener.getAccountManager(), tokenKVV -> { + LoginTokenWB.load(mListener.getAccountManager(), tokenKVV -> { LoginTokenBB.load(mListener.getAccountManager(), tokenBB -> { boolean result = setToken(tokenKVV, tokenBB); mLoginPending = false; @@ -69,7 +69,7 @@ public class Login { } public void isOfflineStoredAvailable(BooleanInterface callback) { - LoginTokenKVV.load(mListener.getAccountManager(), tokenKVV -> { + LoginTokenWB.load(mListener.getAccountManager(), tokenKVV -> { LoginTokenBB.load(mListener.getAccountManager(), tokenBB -> { callback.run(tokenKVV != null && tokenBB != null); }, e -> callback.run(false)); @@ -103,7 +103,7 @@ public class Login { return isLoggedIn(); } - void testLoginToken(@NotNull NetworkCallback> callback, @NotNull NetworkErrorCallback errorCallback) { + void testLoginToken(@NotNull NetworkCallback> callback, @NotNull NetworkErrorCallback errorCallback) { if (mTokenKVV == null) { errorCallback.onError(new NetworkError(100173, -1, "Not logged in!")); return; @@ -115,16 +115,16 @@ public class Login { testLoginToken(mTokenKVV, mTokenBB, callback, errorCallback); } - private void testLoginToken(@NotNull LoginTokenKVV tokenKVV, @NotNull LoginTokenBB tokenBB, @NotNull NetworkCallback> callback, @NotNull NetworkErrorCallback errorCallback) { + private void testLoginToken(@NotNull LoginTokenWB tokenKVV, @NotNull LoginTokenBB tokenBB, @NotNull NetworkCallback> callback, @NotNull NetworkErrorCallback errorCallback) { FULogin mFULogin = new FULogin(getContext()); - new KVVLogin(getContext(), mFULogin).testLoginToken(tokenKVV, tokenKVV1 -> { + new WBLogin(getContext(), mFULogin).testLoginToken(tokenKVV, tokenKVV1 -> { new BBLogin(getContext(), mFULogin).testLoginToken(tokenBB, tokenBB1 -> { callback.onResponse(new Pair<>(tokenKVV1, tokenBB1)); }, errorCallback); }, errorCallback); } - @Nullable public LoginTokenKVV getLoginTokenKVV() { + @Nullable public LoginTokenWB getLoginTokenKVV() { return mTokenKVV; } @@ -132,7 +132,7 @@ public class Login { return mTokenBB; } - void refreshLogin(NetworkCallback> success, NetworkErrorCallback error, int flags) { + void refreshLogin(NetworkCallback> success, NetworkErrorCallback error, int flags) { boolean isFirst = mRefreshCallbacks.isEmpty(); mRefreshCallbacks.add(success, error); if (!isFirst) @@ -140,10 +140,10 @@ public class Login { refreshLoginRunner(success, error, flags); } - private void refreshLoginRunner(NetworkCallback> success, NetworkErrorCallback error, int flags) { + private void refreshLoginRunner(NetworkCallback> success, NetworkErrorCallback error, int flags) { CustomAccountManager manager = mListener.getAccountManager(); if ((flags & LOGOUT_KVV) == LOGOUT_KVV) { - manager.doInvalidateToken(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, ignored -> { + manager.doInvalidateToken(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_WB, ignored -> { refreshLoginRunner(success, error, flags & ~LOGOUT_KVV); }); } else if ((flags & LOGOUT_BB) == LOGOUT_BB) { @@ -178,7 +178,7 @@ public class Login { } } - private boolean setToken(@Nullable LoginTokenKVV tokenKVV, @Nullable LoginTokenBB tokenBB) { + private boolean setToken(@Nullable LoginTokenWB tokenKVV, @Nullable LoginTokenBB tokenBB) { if (tokenKVV == null || tokenBB == null) return false; boolean isOnlyRefresh = mTokenKVV != null; diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java index e1bf0b1..5bd022c 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAnnouncements.java @@ -39,7 +39,7 @@ public class ModulesAnnouncements extends PartModules> { errorCallback.onError(new NetworkError(101204, 500, "Currently running in offline mode!")); return; } - super.get(String.format(Constants.KVV_SERVER_URL+"direct/announcement/site/%s.json?n=999999&d=999999999&_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { + super.get(String.format(Constants.WB_SERVER_URL +"direct/announcement/site/%s.json?n=999999&d=999999999&_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101201, 403, "No announcements retrieved!")); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java index 22e30c8..704f609 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesAssignments.java @@ -39,7 +39,7 @@ public class ModulesAssignments extends PartModules { errorCallback.onError(new NetworkError(101304, 500, "Currently running in offline mode!")); return; } - get(String.format(Constants.KVV_SERVER_URL+"direct/assignment/site/%s.json?_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { + get(String.format(Constants.WB_SERVER_URL +"direct/assignment/site/%s.json?_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101301, 403, "No assignments retrieved!")); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java index 8483c2e..e4ce073 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesEvents.java @@ -46,7 +46,7 @@ public class ModulesEvents extends PartModules { errorCallback.onError(new NetworkError(101404, 500, "Currently running in offline mode!")); return; } - get(String.format(Constants.KVV_SERVER_URL+"direct/calendar/site/%s.json?detailed=true&_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { + get(String.format(Constants.WB_SERVER_URL +"direct/calendar/site/%s.json?detailed=true&_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101401, 403, "No events retrieved!")); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java index 3378546..ebb7547 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesGradebook.java @@ -6,8 +6,6 @@ import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; -import java.util.ArrayList; - import de.sebse.fuplanner.services.kvv.types.Grade; import de.sebse.fuplanner.services.kvv.types.Gradebook; import de.sebse.fuplanner.services.kvv.types.Modules; @@ -39,7 +37,7 @@ public class ModulesGradebook extends PartModules { errorCallback.onError(new NetworkError(101504, 500, "Currently running in offline mode!")); return; } - super.get(String.format(Constants.KVV_SERVER_URL+"direct/gradebook/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { + super.get(String.format(Constants.WB_SERVER_URL +"direct/gradebook/site/%s.json", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101501, 403, "No gradebook retrieved!")); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java index 87ad5ea..d6abd1b 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesList.java @@ -194,7 +194,7 @@ public class ModulesList extends HTTPService { callback.onResponse(modules); return; } - get(Constants.KVV_SERVER_URL+"direct/membership.json?_validateSession=", mLogin.getLoginTokenKVV().getCookies(), response -> { + get(Constants.WB_SERVER_URL +"direct/membership.json?_validateSession=", mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101111, 403, "No membership list retrieved!")); @@ -226,7 +226,7 @@ public class ModulesList extends HTTPService { if (--latch[0] == 0) successCallback.onResponse(modules); continue; } - get(String.format(Constants.KVV_SERVER_URL+"direct/site/%s.json?_validateSession=", courseId), mLogin.getLoginTokenKVV().getCookies(), response1 -> { + get(String.format(Constants.WB_SERVER_URL +"direct/site/%s.json?_validateSession=", courseId), mLogin.getLoginTokenKVV().getCookies(), response1 -> { String body1 = response1.getParsed(); if (body1 == null) { errorCallback.onError(new NetworkError(101113, 403, "No site retrieved!")); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java index e93ac86..b706826 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/ModulesResources.java @@ -4,8 +4,6 @@ import android.content.Context; import android.os.Build; import android.os.Environment; -import androidx.core.content.ContextCompat; - import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; @@ -49,7 +47,7 @@ public class ModulesResources extends PartModules> { errorCallback.onError(new NetworkError(101604, 500, "Currently running in offline mode!")); return; } - get(String.format(Constants.KVV_SERVER_URL+"direct/content/site/%s.json?_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { + get(String.format(Constants.WB_SERVER_URL +"direct/content/site/%s.json?_validateSession=", ID), mLogin.getLoginTokenKVV().getCookies(), response -> { String body = response.getParsed(); if (body == null) { errorCallback.onError(new NetworkError(101601, 403, "No resources retrieved!")); diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/BBLogin.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/BBLogin.java index 42fbc25..04d922f 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/BBLogin.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/BBLogin.java @@ -1,6 +1,7 @@ package de.sebse.fuplanner.services.kvv.sync; import android.content.Context; +import android.os.Bundle; import org.jetbrains.annotations.NotNull; import org.json.JSONException; @@ -16,147 +17,133 @@ import de.sebse.fuplanner.tools.network.NetworkCallback; import de.sebse.fuplanner.tools.network.NetworkError; import de.sebse.fuplanner.tools.network.NetworkErrorCallback; -public class BBLogin extends HTTPService { - private final FULogin mFULogin; - private long lastHash; - private long lastSync; - private static final long MAX_CACHE_TIME = 1000 * 60; // 1 minute +import static de.sebse.fuplanner.services.kvv.Constants.BB_SERVER_URL; + +public class BBLogin extends LoginRoutine { + private FULogin fuLogin; public BBLogin(Context context, FULogin fuLogin) { super(context); - this.mFULogin = fuLogin; + this.fuLogin = fuLogin; } - public void testLoginToken(@NotNull LoginTokenBB token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) { - if (token.hashCode() == lastHash && lastSync + MAX_CACHE_TIME > System.currentTimeMillis() && token.getStudentId() != null) { - callback.onResponse(token); - return; - } - get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/users/?userName=%s", token.getUsername()), token.getCookies(), response -> { + @Override + public void doesAccountExists(@NotNull String username, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error) { + callback.onResponse(true); + } + + @Override + protected LoginTokenBB createUnavailableToken() { + return new LoginTokenBB(); + } + + @Override + protected void checkToken(@NotNull LoginTokenBB token, @NotNull NetworkCallback bundleCallback, @NotNull NetworkErrorCallback error) { + get(String.format(BB_SERVER_URL + "learn/api/public/v1/users/?userName=%s", token.getUsername()), token.getCookies(), response -> { String body = response.getParsed(); if (body == null) { - errorCallback.onError(new NetworkError(100272, 403, "Testing login failed!")); + error.onError(new NetworkError(100272, 403, "Testing BB login failed!")); return; } try { JSONObject json = new JSONObject(body); json = json.getJSONArray("results").getJSONObject(0); - String id = json.getString("id"); - String studentId = json.getString("studentId"); - token.setAdditionals(id, studentId); - lastSync = System.currentTimeMillis(); - lastHash = token.hashCode(); - callback.onResponse(token); + Bundle bundle = new Bundle(); + bundle.putString("id", json.getString("id")); + bundle.putString("studentId", json.getString("studentId")); + bundleCallback.onResponse(bundle); } catch (JSONException e) { - errorCallback.onError(new NetworkError(100271, 403, "Cannot parse profile!")); + error.onError(new NetworkError(100271, 403, "Cannot parse BB profile!")); } - }, error -> errorCallback.onError(new NetworkError(100270, error.networkResponse.statusCode, "Testing login failed!"))); + }, err -> error.onError(new NetworkError(100270, err.networkResponse.statusCode, "Testing BB login failed!"))); } - - - - - - - - - - - - - - - public void doLogin(String username, String password, NetworkCallback callback, NetworkErrorCallback error) { - step1(success1 -> { - String samlLocation = success1.get("Location"); - mFULogin.fulogin(samlLocation, username, password, samlResponse -> { - step5(samlResponse, success5 -> { - String shibsessionKey = success5.get("shibsessionKey"); - String shibsessionName = success5.get("shibsessionName"); - step6(shibsessionKey, shibsessionName, success6 -> { - String s_session_id = success6.get("s_session_id"); - String session_id = success6.get("session_id"); - LoginTokenBB token = new LoginTokenBB(username, s_session_id, session_id); - callback.onResponse(token); + @Override + public void createLoginToken(@NotNull String username, @NotNull String password, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error) { + getSAMLLocation(samlLocation -> { + fuLogin.fulogin(samlLocation, username, password, samlResponse -> { + startShibSession(samlResponse, shibSessionKey -> { + String shibsessionKey = shibSessionKey.getString("shibsessionKey"); + String shibsessionName = shibSessionKey.getString("shibsessionName"); + startSession(shibsessionKey, shibsessionName, sessionCookies -> { + Bundle bundle = new Bundle(); + bundle.putString("username", username); + bundle.putAll(sessionCookies); + LoginTokenBB tokenBB = new LoginTokenBB(bundle); + testToken(tokenBB, callback, error); }, error); }, error); }, error); }, error); } + + /* 1= GET https://lms.fu-berlin.de/lms-apps/login/sso/index.php -> Location-Header: https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState] */ - private void step1(final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - get("https://lms.fu-berlin.de/lms-apps/login/sso/index.php", null, response -> { + private void getSAMLLocation(final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + get(BB_SERVER_URL + "lms-apps/login/sso/index.php", null, response -> { String location = response.getHeaders().get("Location"); - if (location==null) { - errorCallback.onError(new NetworkError(100211, -1, "Error on getting SAML request!")); + if (location == null) { + errorCallback.onError(new NetworkError(100211, -1, "Error on getting BB SAML request!")); return; } - HashMap object = new HashMap<>(); - object.put("Location", location); - callback.onResponse(object); - }, error -> errorCallback.onError(new NetworkError(100210, error.networkResponse.statusCode, "Error on getting SAML request!"))); + callback.onResponse(location); + }, error -> errorCallback.onError(new NetworkError(100210, error.networkResponse.statusCode, "Error on getting BB SAML request!"))); } - - /* 5= POST https://lms.fu-berlin.de/Shibboleth.sso/SAML2/POST + Body: SAMLResponse=[SAML-RESPONSE] + Header: Content-Type: application/x-www-form-urlencoded -> Set-Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] */ - private void step5(String SAMLResponse, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + private void startShibSession(String samlResponse, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { HashMap body = new HashMap<>(); - body.put("SAMLResponse", SAMLResponse); - post("https://lms.fu-berlin.de/Shibboleth.sso/SAML2/POST", null, body, response -> { + body.put("SAMLResponse", samlResponse); + post(BB_SERVER_URL + "Shibboleth.sso/SAML2/POST", null, body, response -> { String cookies = response.getHeaders().get("Set-Cookie"); if (cookies ==null) { - errorCallback.onError(new NetworkError(100251, -1, "Error on starting KVV session!")); + errorCallback.onError(new NetworkError(100251, -1, "Error on starting BB session!")); return; } - HashMap object = new HashMap<>(); - Pattern pattern = Pattern.compile("(_shibsession_[0-9a-f]+)=([^;]+);"); Matcher matcher = pattern.matcher(cookies); if (!matcher.find()) { - errorCallback.onError(new NetworkError(100252, -1, "Error on starting KVV session!")); + errorCallback.onError(new NetworkError(100252, -1, "Error on starting BB session!")); } - object.put("shibsessionKey", matcher.group(1)); - object.put("shibsessionName", matcher.group(2)); - callback.onResponse(object); - }, error -> errorCallback.onError(new NetworkError(100250, error.networkResponse.statusCode, "Error on starting KVV session!"))); + Bundle bundle = new Bundle(); + bundle.putString("shibsessionKey", matcher.group(1)); + bundle.putString("shibsessionName", matcher.group(2)); + + callback.onResponse(bundle); + }, error -> errorCallback.onError(new NetworkError(100250, error.networkResponse.statusCode, "Error on starting BB session!"))); } - /* 6= https://lms.fu-berlin.de/webapps/bb-auth-provider-shibboleth-bb_bb60/execute/shibbolethLogin?returnUrl=https://lms.fu-berlin.de/webapps/portal/execute/defaultTab&authProviderId=_3_1 + Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] -> Set-Cookie: JSESSIONID: [JSESSION-KVV] */ - private void step6(String shibsessionKey, String shibsessionName, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + private void startSession(String shibsessionKey, String shibsessionName, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { HashMap cookies = new HashMap<>(); cookies.put(shibsessionKey, shibsessionName); - get("https://lms.fu-berlin.de/webapps/bb-auth-provider-shibboleth-bb_bb60/execute/shibbolethLogin?returnUrl=https://lms.fu-berlin.de/webapps/portal/execute/defaultTab&authProviderId=_3_1", cookies, response -> { - String cookies1 = response.getHeaders().get("Set-Cookie"); - if (cookies1 ==null) { - errorCallback.onError(new NetworkError(100261, -1, "Cannot finish login process!")); + get(BB_SERVER_URL + "webapps/bb-auth-provider-shibboleth-bb_bb60/execute/shibbolethLogin?returnUrl=https://lms.fu-berlin.de/webapps/portal/execute/defaultTab&authProviderId=_3_1", cookies, response -> { + String cookiesSet = response.getHeaders().get("Set-Cookie"); + if (cookiesSet == null) { + errorCallback.onError(new NetworkError(100261, -1, "Cannot finish BB login process!")); return; } - HashMap object; try { - object = getCookie(cookies1, new String[]{"session_id", "s_session_id"}); + Bundle bundle = getCookie(cookiesSet, new String[]{"session_id", "s_session_id"}); + callback.onResponse(bundle); } catch (NoSuchFieldException e) { - errorCallback.onError(new NetworkError(100262, -1, "Cannot finish login process!")); - return; + errorCallback.onError(new NetworkError(100262, -1, "Cannot finish BB login process!")); } - callback.onResponse(object); - }, error -> errorCallback.onError(new NetworkError(100260, error.networkResponse.statusCode, "Cannot finish login process!"))); + }, error -> errorCallback.onError(new NetworkError(100260, error.networkResponse.statusCode, "Cannot finish BB login process!"))); } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/FULogin.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/FULogin.java index 220a230..43284fe 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/FULogin.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/FULogin.java @@ -1,12 +1,16 @@ package de.sebse.fuplanner.services.kvv.sync; import android.content.Context; +import android.os.Bundle; import java.util.HashMap; import java.util.regex.Matcher; import java.util.regex.Pattern; import androidx.annotation.Nullable; + +import org.jetbrains.annotations.NotNull; + import de.sebse.fuplanner.R; import de.sebse.fuplanner.tools.Preferences; import de.sebse.fuplanner.tools.network.HTTPService; @@ -19,20 +23,20 @@ public class FULogin extends HTTPService { super(context); } - public void fulogin(String requestURI, String username, String password, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + public void fulogin(String samlRequestUri, String username, String password, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { String old_shib_idp_session = Preferences.getString(getContext(), R.string.pref_shib_idp_session); - step2(requestURI, old_shib_idp_session, success2 -> { - String samlResp = success2.get("SAMLResponse"); - if (samlResp != null) { - callback.onResponse(samlResp); + startSamlRequest(samlRequestUri, old_shib_idp_session, samlRequest -> { + if (samlRequest.containsKey("SAMLResponse")) { + callback.onResponse(samlRequest.getString("SAMLResponse", "")); return; } - String fuJSESSIONID = success2.get("JSESSIONID"); - step3(fuJSESSIONID, success3 -> { - step4(username, password, fuJSESSIONID, success4 -> { - String shib_idp_session = success4.get("shib_idp_session"); + + String JSESSIONID = samlRequest.getString("JSESSIONID"); + openLoginForm(JSESSIONID, success -> { + finishLogin(username, password, JSESSIONID, samlResp -> { + String shib_idp_session = samlResp.getString("shib_idp_session"); Preferences.setString(getContext(), R.string.pref_shib_idp_session, shib_idp_session); - String samlResponse = success4.get("SAMLResponse"); + String samlResponse = samlResp.getString("SAMLResponse"); if (samlResponse != null) callback.onResponse(samlResponse); else @@ -47,24 +51,24 @@ public class FULogin extends HTTPService { -> Set-Cookie: JSESSIONID=[JSESSION-FU] -> Location: /idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1 */ - private void step2(String url, @Nullable String shib_idp_session, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { + private void startSamlRequest(String samlRequestUri, @Nullable String shib_idp_session, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { HashMap cookiesReq = null; if (shib_idp_session != null) { cookiesReq = new HashMap<>(); cookiesReq.put("shib_idp_session", shib_idp_session); } - get(url, cookiesReq, response -> { + get(samlRequestUri, cookiesReq, response -> { String body = response.getParsed(); if (body != null) { Pattern pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)"); Matcher matcher = pattern.matcher(body); if (!matcher.find()) { - errorCallback.onError(new NetworkError(100344, -1, "Error on getting SAML response!")); + errorCallback.onError(new NetworkError(100344, -1, "Error on getting FU SAML response!")); return; } - HashMap object = new HashMap<>(); - object.put("SAMLResponse", matcher.group(1)); - callback.onResponse(object); + Bundle bundle = new Bundle(); + bundle.putString("SAMLResponse", matcher.group(1)); + callback.onResponse(bundle); return; } String cookies = response.getHeaders().get("Set-Cookie"); @@ -72,14 +76,12 @@ public class FULogin extends HTTPService { errorCallback.onError(new NetworkError(100321, -1, "Error on starting FU session!")); return; } - HashMap object; try { - object = getCookie(cookies, new String[]{"JSESSIONID"}); + Bundle bundle = getCookie(cookies, new String[]{"JSESSIONID"}); + callback.onResponse(bundle); } catch (NoSuchFieldException e) { errorCallback.onError(new NetworkError(100322, -1, "Error on starting FU session!")); - return; } - callback.onResponse(object); }, error -> errorCallback.onError(new NetworkError(100320, error.networkResponse.statusCode, "Error on starting FU session!"))); } @@ -87,12 +89,12 @@ public class FULogin extends HTTPService { 3= GET [Location-Header 2] + Cookie: JSESSIONID=[JSESSION-FU] */ - private void step3(String JSESSIONID_FU, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + private void openLoginForm(String JSESSIONID_FU, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { HashMap cookies = new HashMap<>(); cookies.put("JSESSIONID", JSESSIONID_FU); head("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> { callback.onResponse(true); - }, error -> errorCallback.onError(new NetworkError(100330, error.networkResponse.statusCode, "Error starting login page!"))); + }, error -> errorCallback.onError(new NetworkError(100330, error.networkResponse.statusCode, "Error starting FU login page!"))); } /* @@ -104,28 +106,28 @@ public class FULogin extends HTTPService { -> Set-Cookie: shib_idp_session=[SHIB-IDP-SESSION] -> Body SAMLResponse-Input-value */ - private void step4(String username, String password, String JSESSIONID_FU, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - HashMap cookies = new HashMap<>(); - cookies.put("JSESSIONID", JSESSIONID_FU); + private void finishLogin(String username, String password, String JSESSIONID_FU, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + HashMap cookiesReq = new HashMap<>(); + cookiesReq.put("JSESSIONID", JSESSIONID_FU); HashMap body = new HashMap<>(); body.put("j_username", username); body.put("j_password", password); body.put("_eventId_proceed", ""); - post("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, body, response -> { + post("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookiesReq, body, response -> { String content = response.getParsed(); if (content == null) { - errorCallback.onError(new NetworkError(100343, -1, "Error on getting SAML response!")); + errorCallback.onError(new NetworkError(100343, -1, "Error on getting FU SAML response!")); return; } - String cookies1 = response.getHeaders().get("Set-Cookie"); - if (cookies1 ==null) { + String cookies = response.getHeaders().get("Set-Cookie"); + if (cookies == null) { errorCallback.onError(new NetworkError(100341, -1, "Error on logging in to FU Identity Server!")); return; } - HashMap object; + Bundle bundle; try { - object = getCookie(cookies1, new String[]{"shib_idp_session"}); + bundle = getCookie(cookies, new String[]{"shib_idp_session"}); } catch (NoSuchFieldException e) { errorCallback.onError(new NetworkError(100342, -1, "Error on logging in to FU Identity Server!")); return; @@ -136,8 +138,8 @@ public class FULogin extends HTTPService { errorCallback.onError(new NetworkError(100344, -1, "Error on getting SAML response!")); return; } - object.put("SAMLResponse", matcher.group(1)); - callback.onResponse(object); + bundle.putString("SAMLResponse", matcher.group(1)); + callback.onResponse(bundle); }, error -> errorCallback.onError(new NetworkError(100345, error.networkResponse.statusCode, "Error on logging in to FU Identity Server!"))); } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVLogin.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVLogin.java deleted file mode 100644 index 6e82d36..0000000 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVLogin.java +++ /dev/null @@ -1,176 +0,0 @@ -package de.sebse.fuplanner.services.kvv.sync; - -import android.content.Context; - -import org.jetbrains.annotations.NotNull; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import de.sebse.fuplanner.services.kvv.Constants; -import de.sebse.fuplanner.services.kvv.types.LoginTokenKVV; -import de.sebse.fuplanner.tools.network.HTTPService; -import de.sebse.fuplanner.tools.network.NetworkCallback; -import de.sebse.fuplanner.tools.network.NetworkError; -import de.sebse.fuplanner.tools.network.NetworkErrorCallback; - -public class KVVLogin extends HTTPService { - private final FULogin mFULogin; - private long lastHash; - private long lastSync; - private static final long MAX_CACHE_TIME = 1000 * 60; // 1 minute - - public static final String KVV_SERVER_URL = Constants.KVV_SERVER_URL; - - public KVVLogin(Context context, FULogin fuLogin) { - super(context); - this.mFULogin = fuLogin; - } - - - public void testLoginToken(@NotNull LoginTokenKVV token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) { - if (token.hashCode() == lastHash && lastSync + MAX_CACHE_TIME > System.currentTimeMillis() && token.getFullName() != null) { - callback.onResponse(token); - return; - } - get(String.format(KVV_SERVER_URL+"direct/profile/%s.json", token.getUsername()), token.getCookies(), response -> { - String body = response.getParsed(); - if (body == null) { - errorCallback.onError(new NetworkError(100172, 403, "Testing login failed!")); - return; - } - try { - JSONObject json = new JSONObject(body); - String displayName = json.getString("displayName"); - String email = json.getString("email"); - token.setAdditionals(displayName, email); - lastSync = System.currentTimeMillis(); - lastHash = token.hashCode(); - callback.onResponse(token); - } catch (JSONException e) { - errorCallback.onError(new NetworkError(100171, 403, "Cannot parse profile!")); - } - }, error -> errorCallback.onError(new NetworkError(100170, error.networkResponse.statusCode, "Testing login failed!"))); - } - - - - - - - - - - - - - - - - public void doLogin(String username, String password, NetworkCallback callback, NetworkErrorCallback error) { - step0(username, success -> { - step1(success1 -> { - String samlLocation = success1.get("Location"); - mFULogin.fulogin(samlLocation, username, password, samlResponse -> { - step5(samlResponse, success5 -> { - String shibsessionKey = success5.get("shibsessionKey"); - String shibsessionName = success5.get("shibsessionName"); - step6(shibsessionKey, shibsessionName, success6 -> { - String kvvJSESSIONID = success6.get("JSESSIONID"); - LoginTokenKVV token = new LoginTokenKVV(username, kvvJSESSIONID); - callback.onResponse(token); - }, error); - }, error); - }, error); - }, error); - }, error); - } - - private void step0(String username, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { - get(String.format(KVV_SERVER_URL+"direct/profile/%s", username), null, result -> { - callback.onResponse(true); - }, error -> { - if (error.networkResponse.statusCode == 500) { - errorCallback.onError(new NetworkError(100101, error.networkResponse.statusCode, "KVV not available!")); - } else { - callback.onResponse(true); - } - }); - } - - /* - 1= GET https://mycampus.imp.fu-berlin.de/Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub - -> Location-Header: https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState] - */ - private void step1(final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - get(KVV_SERVER_URL+"Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub", null, response -> { - String location = response.getHeaders().get("Location"); - if (location==null) { - errorCallback.onError(new NetworkError(100111, -1, "Error on getting SAML request!")); - return; - } - HashMap object = new HashMap<>(); - object.put("Location", location); - callback.onResponse(object); - }, error -> errorCallback.onError(new NetworkError(100110, error.networkResponse.statusCode, "Error on getting SAML request!"))); - } - - /* - 5= POST https://mycampus.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST - + Body: SAMLResponse=[SAML-RESPONSE] - + Header: Content-Type: application/x-www-form-urlencoded - -> Set-Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] - */ - private void step5(String SAMLResponse, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - HashMap body = new HashMap<>(); - body.put("SAMLResponse", SAMLResponse); - post(KVV_SERVER_URL+"Shibboleth.sso/SAML2/POST", null, body, response -> { - String cookies = response.getHeaders().get("Set-Cookie"); - if (cookies ==null) { - errorCallback.onError(new NetworkError(100151, -1, "Error on starting KVV session!")); - return; - } - HashMap object = new HashMap<>(); - - - Pattern pattern = Pattern.compile("(_shibsession_[0-9a-f]+)=([^;]+);"); - Matcher matcher = pattern.matcher(cookies); - if (!matcher.find()) { - errorCallback.onError(new NetworkError(100152, -1, "Error on starting KVV session!")); - } - object.put("shibsessionKey", matcher.group(1)); - object.put("shibsessionName", matcher.group(2)); - - callback.onResponse(object); - }, error -> errorCallback.onError(new NetworkError(100150, error.networkResponse.statusCode, "Error on starting KVV session!"))); - } - - - /* - 6= https://mycampus.imp.fu-berlin.de/sakai-login-tool/container - + Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] - -> Set-Cookie: JSESSIONID: [JSESSION-KVV] - */ - private void step6(String shibsessionKey, String shibsessionName, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) { - HashMap cookies = new HashMap<>(); - cookies.put(shibsessionKey, shibsessionName); - get(KVV_SERVER_URL+"sakai-login-tool/container", cookies, response -> { - String cookies1 = response.getHeaders().get("Set-Cookie"); - if (cookies1 ==null) { - errorCallback.onError(new NetworkError(100161, -1, "Cannot finish login process!")); - return; - } - HashMap object; - try { - object = getCookie(cookies1, new String[]{"JSESSIONID"}); - } catch (NoSuchFieldException e) { - errorCallback.onError(new NetworkError(100162, -1, "Cannot finish login process!")); - return; - } - callback.onResponse(object); - }, error -> errorCallback.onError(new NetworkError(100160, error.networkResponse.statusCode, "Cannot finish login process!"))); - } -} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/LoginRoutine.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/LoginRoutine.java new file mode 100644 index 0000000..e4dd004 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/LoginRoutine.java @@ -0,0 +1,55 @@ +package de.sebse.fuplanner.services.kvv.sync; + +import android.content.Context; +import android.os.Bundle; + +import org.jetbrains.annotations.NotNull; + +import de.sebse.fuplanner.services.kvv.types.LoginToken; +import de.sebse.fuplanner.tools.network.HTTPService; +import de.sebse.fuplanner.tools.network.NetworkCallback; +import de.sebse.fuplanner.tools.network.NetworkErrorCallback; + +public abstract class LoginRoutine extends HTTPService { + private long lastHash; + private long lastSync; + private static final long MAX_CACHE_TIME = 1000 * 60; // 1 minute + + public LoginRoutine(Context context) { + super(context); + } + + public final void testToken(@NotNull T token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error) { + if (token.hashCode() == lastHash && lastSync + MAX_CACHE_TIME > System.currentTimeMillis() && token.hasAdditionals()) { + callback.onResponse(token); + return; + } + + checkToken(token, (bundle) -> { + token.setAdditionals(bundle); + lastSync = System.currentTimeMillis(); + lastHash = token.hashCode(); + callback.onResponse(token); + }, error); + } + + public abstract void doesAccountExists(@NotNull String username, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error); + + protected abstract void checkToken(@NotNull T token, @NotNull NetworkCallback bundleCallback, @NotNull NetworkErrorCallback error); + + public final void login(@NotNull String username, @NotNull String password, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error) { + doesAccountExists(username, success -> { + if (success) { + createLoginToken(username, password, callback, error); + return; + } else { + callback.onResponse(createUnavailableToken()); + return; + } + }, error); + } + + protected abstract void createLoginToken(@NotNull String username, @NotNull String password, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error); + + protected abstract T createUnavailableToken(); +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVContentProvider.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/ModuleContentProvider.java similarity index 100% rename from app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVContentProvider.java rename to app/src/main/java/de/sebse/fuplanner/services/kvv/sync/ModuleContentProvider.java diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVSyncAdapter.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/ModuleSyncAdapter.java similarity index 100% rename from app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVSyncAdapter.java rename to app/src/main/java/de/sebse/fuplanner/services/kvv/sync/ModuleSyncAdapter.java diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVSyncService.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/ModuleSyncService.java similarity index 100% rename from app/src/main/java/de/sebse/fuplanner/services/kvv/sync/KVVSyncService.java rename to app/src/main/java/de/sebse/fuplanner/services/kvv/sync/ModuleSyncService.java diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/WBLogin.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/WBLogin.java new file mode 100644 index 0000000..1bab1ec --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/sync/WBLogin.java @@ -0,0 +1,158 @@ +package de.sebse.fuplanner.services.kvv.sync; + +import android.content.Context; +import android.os.Bundle; + +import org.jetbrains.annotations.NotNull; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +import de.sebse.fuplanner.services.kvv.types.LoginTokenWB; +import de.sebse.fuplanner.tools.network.NetworkCallback; +import de.sebse.fuplanner.tools.network.NetworkError; +import de.sebse.fuplanner.tools.network.NetworkErrorCallback; + +import static de.sebse.fuplanner.services.kvv.Constants.WB_SERVER_URL; + +public class WBLogin extends LoginRoutine { + private final FULogin fuLogin; + + public WBLogin(Context context, FULogin fuLogin) { + super(context); + this.fuLogin = fuLogin; + } + + @Override + public void doesAccountExists(@NotNull String username, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error) { + callback.onResponse(true); + get(String.format(WB_SERVER_URL + "direct/profile/%s.json", username), null, response -> { + callback.onResponse(true); + }, err -> { + if (err.networkResponse.statusCode == 403) { + callback.onResponse(true); + } else { + callback.onResponse(false); + } + }); + } + + @Override + protected LoginTokenWB createUnavailableToken() { + return new LoginTokenWB(); + } + + @Override + protected void checkToken(@NotNull LoginTokenWB token, @NotNull NetworkCallback bundleCallback, @NotNull NetworkErrorCallback error) { + get(String.format(WB_SERVER_URL + "direct/profile/%s.json", token.getUsername()), token.getCookies(), response -> { + String body = response.getParsed(); + if (body == null) { + error.onError(new NetworkError(100172, 403, "Testing WB login failed!")); + return; + } + try { + JSONObject json = new JSONObject(body); + Bundle bundle = new Bundle(); + bundle.putString("fullName", json.getString("displayName")); + bundle.putString("email", json.getString("email")); + bundleCallback.onResponse(bundle); + } catch (JSONException e) { + error.onError(new NetworkError(100171, 403, "Cannot parse WB profile!")); + } + }, err -> error.onError(new NetworkError(100170, err.networkResponse.statusCode, "Testing WB login failed!"))); + } + + @Override + public void createLoginToken(@NotNull String username, @NotNull String password, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback error) { + getSAMLLocation(samlLocation -> { + fuLogin.fulogin(samlLocation, username, password, samlResponse -> { + startShibSession(samlResponse, shibSessionKey -> { + String shibsessionKey = shibSessionKey.getString("shibsessionKey"); + String shibsessionName = shibSessionKey.getString("shibsessionName"); + startSession(shibsessionKey, shibsessionName, sessionCookies -> { + Bundle bundle = new Bundle(); + bundle.putString("username", username); + bundle.putAll(sessionCookies); + LoginTokenWB tokenWB = new LoginTokenWB(bundle); + testToken(tokenWB, callback, error); + }, error); + }, error); + }, error); + }, error); + } + + + + /* + 1= GET https://mycampus.imp.fu-berlin.de/Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub + -> Location-Header: https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?SAMLResponse=[SAMLResponse]&RelayState=[RelayState] + */ + private void getSAMLLocation(final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + get(WB_SERVER_URL + "Shibboleth.sso/Login?entityID=https://identity.fu-berlin.de/idp-fub", null, response -> { + String location = response.getHeaders().get("Location"); + if (location == null) { + errorCallback.onError(new NetworkError(100111, -1, "Error on getting WB SAML request!")); + return; + } + callback.onResponse(location); + }, error -> errorCallback.onError(new NetworkError(100110, error.networkResponse.statusCode, "Error on getting WB SAML request!"))); + } + + /* + 5= POST https://mycampus.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST + + Body: SAMLResponse=[SAML-RESPONSE] + + Header: Content-Type: application/x-www-form-urlencoded + -> Set-Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] + */ + private void startShibSession(String samlResponse, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + HashMap body = new HashMap<>(); + body.put("SAMLResponse", samlResponse); + post(WB_SERVER_URL + "Shibboleth.sso/SAML2/POST", null, body, response -> { + String cookies = response.getHeaders().get("Set-Cookie"); + if (cookies ==null) { + errorCallback.onError(new NetworkError(100151, -1, "Error on starting WB session!")); + return; + } + + + Pattern pattern = Pattern.compile("(_shibsession_[0-9a-f]+)=([^;]+);"); + Matcher matcher = pattern.matcher(cookies); + if (!matcher.find()) { + errorCallback.onError(new NetworkError(100152, -1, "Error on starting WB session!")); + } + + Bundle bundle = new Bundle(); + bundle.putString("shibsessionKey", matcher.group(1)); + bundle.putString("shibsessionName", matcher.group(2)); + + callback.onResponse(bundle); + }, error -> errorCallback.onError(new NetworkError(100150, error.networkResponse.statusCode, "Error on starting WB session!"))); + } + + + /* + 6= https://mycampus.imp.fu-berlin.de/sakai-login-tool/container + + Cookie: _shibsession_[SESS-NR]: [SESS-VALUE] + -> Set-Cookie: JSESSIONID: [JSESSION-KVV] + */ + private void startSession(String shibsessionKey, String shibsessionName, final NetworkCallback callback, final NetworkErrorCallback errorCallback) { + HashMap cookies = new HashMap<>(); + cookies.put(shibsessionKey, shibsessionName); + get(WB_SERVER_URL + "sakai-login-tool/container", cookies, response -> { + String cookies1 = response.getHeaders().get("Set-Cookie"); + if (cookies1 ==null) { + errorCallback.onError(new NetworkError(100161, -1, "Cannot finish WB login process!")); + return; + } + try { + Bundle bundle = getCookie(cookies1, new String[]{"JSESSIONID"}); + callback.onResponse(bundle); + } catch (NoSuchFieldException e) { + errorCallback.onError(new NetworkError(100162, -1, "Cannot finish WB login process!")); + } + }, error -> errorCallback.onError(new NetworkError(100160, error.networkResponse.statusCode, "Cannot finish WB login process!"))); + } +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginToken.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginToken.java new file mode 100644 index 0000000..b1a58b3 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginToken.java @@ -0,0 +1,123 @@ +package de.sebse.fuplanner.services.kvv.types; + +import android.os.Bundle; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; +import java.util.Objects; + +import de.sebse.fuplanner.services.fulogin.AccountGeneral; +import de.sebse.fuplanner.tools.CustomAccountManager; + +public abstract class LoginToken { + private boolean isExpanded = false; + private boolean isAvailable = false; + + LoginToken(@NotNull CustomAccountManager manager, @NotNull LoginTokenInterface callback, @NotNull CustomAccountManager.ExceptionInterface errorCallback) { + if (!manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE)) { + callback.run(null); + return; + } + manager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD, tokenString -> { + if (tokenString == null) { + callback.run(null); + return; + } + fromString(tokenString); + callback.run(this); + }, errorCallback); + } + + LoginToken() { + super(); + } + + LoginToken(Bundle bundle) { + super(); + init(bundle); + } + + protected abstract String getAccountType(); + + protected void init(Bundle bundle) { + isAvailable = true; + } + + public void setAdditionals(Bundle bundle) { + isExpanded = true; + isAvailable = true; + } + + public final boolean hasAdditionals() { + return isExpanded; + } + + public void setUnavailable() { + isExpanded = false; + isAvailable = false; + } + + public final void unsetAdditionals() { + isExpanded = false; + } + + public final void fromString(String jsonString) { + try { + JSONObject json = new JSONObject(jsonString); + this.isAvailable = json.getBoolean("isAvailable"); + this.isExpanded = json.getBoolean("isExpanded"); + jsonToObject(json); + } catch (JSONException e) { + e.printStackTrace(); + } + } + + @NotNull + public final String toString() { + JSONObject json = null; + try { + json = objectToJson(); + json.put("isAvailable", isAvailable); + json.put("isExpanded", isExpanded); + } catch (JSONException e) { + e.printStackTrace(); + } + if (json != null) { + return json.toString(); + } + return ""; + } + + protected abstract void jsonToObject(JSONObject json) throws JSONException; + + protected abstract JSONObject objectToJson() throws JSONException; + + public abstract HashMap getCookies(); + + public final String getCookieString() { + StringBuilder result = new StringBuilder(); + HashMap cookies = this.getCookies(); + for (String header: cookies.keySet()) { + result.append(header).append("=").append(cookies.get(header)).append(";"); + } + return result.substring(0, result.length()-1); + } + + public final boolean isExpanded() { + return isExpanded; + } + + public final boolean isAvailable() { + return isAvailable; + } + + public interface LoginTokenInterface { + void run(LoginToken token); + } + + public abstract boolean isOtherUser(String user); +} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenBB.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenBB.java index 200fc05..fa01f4b 100644 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenBB.java +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenBB.java @@ -1,7 +1,10 @@ package de.sebse.fuplanner.services.kvv.types; +import android.os.Bundle; + import com.google.android.gms.common.internal.Objects; +import org.jetbrains.annotations.NotNull; import org.json.JSONException; import org.json.JSONObject; @@ -16,66 +19,59 @@ import de.sebse.fuplanner.tools.CustomAccountManager; * Created by sebastian on 29.10.17. */ -public class LoginTokenBB { - private final String s_session_id; - private final String session_id; - private final String username; - private boolean isAvailable = true; +public class LoginTokenBB extends LoginToken { + private String s_session_id; + private String session_id; + private String username; @Nullable private String id; @Nullable private String studentId; - public LoginTokenBB(String username, String s_session_id, String session_id) { - this.username = username; - this.s_session_id = s_session_id; - this.session_id = session_id; + public LoginTokenBB() { + super(); } - public static void load(CustomAccountManager manager, LoginTokenInterface callback, CustomAccountManager.ExceptionInterface errorCallback) { - if (!manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE)) { - callback.run(null); - return; - } - manager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD, tokenString -> { - if (tokenString == null) { - callback.run(null); - return; - } - callback.run(LoginTokenBB.fromJsonString(tokenString)); - }, errorCallback); + public LoginTokenBB(Bundle bundle) { + super(bundle); } - public static boolean hasAccounts(CustomAccountManager manager) { - return manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE); + @Override + protected void init(Bundle bundle) { + super.init(bundle); + this.username = bundle.getString("username"); + this.s_session_id = bundle.getString("s_session_id"); + this.session_id = bundle.getString("session_id"); } - public void delete(CustomAccountManager manager) { - manager.deleteAccount(AccountGeneral.ACCOUNT_TYPE); + @Override + protected String getAccountType() { + return AccountGeneral.AUTHTOKEN_TYPE_BLACKBOARD; } - public void setAdditionals(String id, String studentId) { - this.id = id; - this.studentId = studentId; - this.isAvailable = true; + @Override + public void setAdditionals(Bundle bundle) { + super.setAdditionals(bundle); + this.id = bundle.getString("id"); + this.studentId = bundle.getString("studentId"); } - public void setNotAvailable() { + @Override + public void setUnavailable() { + super.setUnavailable(); this.id = null; this.studentId = null; - this.isAvailable = false; - } - - public boolean isAvailable() { - return isAvailable; } + @NotNull public String getUsername() { return username; } - private String getSessionId() { + @NotNull + public String getSessionId() { return session_id; } + @NotNull public String getSSessionId() { return s_session_id; } @@ -90,6 +86,7 @@ public class LoginTokenBB { return studentId; } + @Override public HashMap getCookies() { HashMap cookies = new HashMap<>(); cookies.put("session_id", getSessionId()); @@ -97,55 +94,40 @@ public class LoginTokenBB { return cookies; } + @Override public boolean isOtherUser(String username) { return !this.getUsername().equals(username); } - @NonNull @Override - public String toString() { - StringBuilder result = new StringBuilder(); - HashMap cookies = this.getCookies(); - for (String header: cookies.keySet()) { - result.append(header).append("=").append(cookies.get(header)).append(";"); - } - return result.substring(0, result.length()-1); - } - - public String toJsonString() { + protected JSONObject objectToJson() throws JSONException { JSONObject json = new JSONObject(); - try { + if (isAvailable()) { json.put("s_session_id", s_session_id); json.put("session_id", session_id); json.put("username", username); + } + if (isExpanded()) { json.put("id", id); json.put("studentId", studentId); - json.put("isAvailable", isAvailable); - } catch (JSONException e) { - return null; } - return json.toString(); + return json; } - private static LoginTokenBB fromJsonString(String tokenString) { - try { - JSONObject json = new JSONObject(tokenString); - LoginTokenBB token = new LoginTokenBB( - json.getString("username"), - json.getString("s_session_id"), - json.getString("session_id")); - if (!json.isNull("id")) - token.setAdditionals( - json.getString("id"), - json.getString("studentId") - ); - if (!json.optBoolean("isAvailable", true)) { - token.setNotAvailable(); - } - return token; - } catch (JSONException e) { - e.printStackTrace(); - return null; + @Override + protected void jsonToObject(JSONObject json) throws JSONException { + if (isAvailable()) { + Bundle bundle = new Bundle(); + bundle.putString("username", json.getString("username")); + bundle.putString("s_session_id", json.getString("s_session_id")); + bundle.putString("session_id", json.getString("session_id")); + init(bundle); + } + if (isExpanded()) { + Bundle bundle = new Bundle(); + bundle.putString("id", json.getString("id")); + bundle.putString("studentId", json.getString("studentId")); + setAdditionals(bundle); } } @@ -153,8 +135,4 @@ public class LoginTokenBB { public int hashCode() { return Objects.hashCode(s_session_id, session_id, username, id, studentId); } - - public interface LoginTokenInterface { - void run(LoginTokenBB token); - } } diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenKVV.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenKVV.java deleted file mode 100644 index 190ed3b..0000000 --- a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenKVV.java +++ /dev/null @@ -1,152 +0,0 @@ -package de.sebse.fuplanner.services.kvv.types; - -import com.google.android.gms.common.internal.Objects; - -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.HashMap; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; -import de.sebse.fuplanner.services.fulogin.AccountGeneral; -import de.sebse.fuplanner.tools.CustomAccountManager; - -/** - * Created by sebastian on 29.10.17. - */ - -public class LoginTokenKVV { - private final String username; - private final String JSESSIONID; - private boolean isAvailable = true; - @Nullable private String fullName; - @Nullable private String email; - - public LoginTokenKVV(String username, String JSESSIONID) { - this.username = username; - this.JSESSIONID = JSESSIONID; - } - - public static void load(CustomAccountManager manager, LoginTokenInterface callback, CustomAccountManager.ExceptionInterface errorCallback) { - if (!manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE)) { - callback.run(null); - return; - } - manager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, tokenString -> { - if (tokenString == null) { - callback.run(null); - return; - } - callback.run(LoginTokenKVV.fromJsonString(tokenString)); - }, errorCallback); - } - - public static boolean hasAccounts(CustomAccountManager manager) { - return manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE); - } - - public void delete(CustomAccountManager manager) { - manager.deleteAccount(AccountGeneral.ACCOUNT_TYPE); - } - - public void setAdditionals(String fullName, String email) { - this.fullName = fullName; - this.email = email; - this.isAvailable = true; - } - - public void setNotAvailable() { - this.fullName = null; - this.email = null; - this.isAvailable = false; - } - - public boolean isAvailable() { - return isAvailable; - } - - public String getUsername() { - return username; - } - - private String getJSESSIONID() { - return JSESSIONID; - } - - @Nullable - public String getFullName() { - return fullName; - } - - @Nullable - public String getEmail() { - return email; - } - - public HashMap getCookies() { - HashMap cookies = new HashMap<>(); - cookies.put("JSESSIONID", getJSESSIONID()); - cookies.put("pasystem_timezone_ok", "true"); - return cookies; - } - - public boolean isOtherUser(String username) { - return !this.getUsername().equals(username); - } - - @NonNull - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - HashMap cookies = this.getCookies(); - for (String header: cookies.keySet()) { - result.append(header).append("=").append(cookies.get(header)).append(";"); - } - return result.substring(0, result.length()-1); - } - - public String toJsonString() { - JSONObject json = new JSONObject(); - try { - json.put("username", username); - json.put("JSESSIONID", JSESSIONID); - json.put("fullName", fullName); - json.put("email", email); - json.put("isAvailable", isAvailable); - } catch (JSONException e) { - return null; - } - return json.toString(); - } - - private static LoginTokenKVV fromJsonString(String tokenString) { - try { - JSONObject json = new JSONObject(tokenString); - LoginTokenKVV token = new LoginTokenKVV( - json.getString("username"), - json.getString("JSESSIONID")); - if (!json.isNull("fullName")) - token.setAdditionals( - json.getString("fullName"), - json.getString("email") - ); - if (!json.optBoolean("isAvailable", true)) { - token.setNotAvailable(); - } - return token; - } catch (JSONException e) { - e.printStackTrace(); - return null; - } - } - - @Override - public int hashCode() { - return Objects.hashCode(username, JSESSIONID, fullName, email); - } - - public interface LoginTokenInterface { - void run(LoginTokenKVV token); - } -} diff --git a/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenWB.java b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenWB.java new file mode 100644 index 0000000..fbeabd0 --- /dev/null +++ b/app/src/main/java/de/sebse/fuplanner/services/kvv/types/LoginTokenWB.java @@ -0,0 +1,126 @@ +package de.sebse.fuplanner.services.kvv.types; + +import android.os.Bundle; + +import com.google.android.gms.common.internal.Objects; + +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.HashMap; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import de.sebse.fuplanner.services.fulogin.AccountGeneral; +import de.sebse.fuplanner.tools.CustomAccountManager; + +/** + * Created by sebastian on 29.10.17. + */ + +public class LoginTokenWB extends LoginToken { + private String username; + private String JSESSIONID; + @Nullable private String fullName; + @Nullable private String email; + + public LoginTokenWB() { + super(); + } + + public LoginTokenWB(Bundle bundle) { + super(bundle); + } + + @Override + protected void init(Bundle bundle) { + super.init(bundle); + this.username = bundle.getString("username"); + this.JSESSIONID = bundle.getString("JSESSIONID"); + } + + @Override + protected String getAccountType() { + return AccountGeneral.AUTHTOKEN_TYPE_WB; + } + + @Override + public void setAdditionals(Bundle bundle) { + super.setAdditionals(bundle); + this.fullName = bundle.getString("fullName"); + this.email = bundle.getString("email"); + } + + @Override + public void setUnavailable() { + super.setUnavailable(); + this.fullName = null; + this.email = null; + } + + public String getUsername() { + return username; + } + + private String getJSESSIONID() { + return JSESSIONID; + } + + @Nullable + public String getFullName() { + return fullName; + } + + @Nullable + public String getEmail() { + return email; + } + + @Override + public HashMap getCookies() { + HashMap cookies = new HashMap<>(); + cookies.put("JSESSIONID", getJSESSIONID()); + cookies.put("pasystem_timezone_ok", "true"); + return cookies; + } + + @Override + public boolean isOtherUser(String username) { + return !this.getUsername().equals(username); + } + + @Override + protected JSONObject objectToJson() throws JSONException { + JSONObject json = new JSONObject(); + if (isAvailable()) { + json.put("username", username); + json.put("JSESSIONID", JSESSIONID); + } + if (isExpanded()) { + json.put("fullName", fullName); + json.put("email", email); + } + return json; + } + + @Override + protected void jsonToObject(JSONObject json) throws JSONException { + if (isAvailable()) { + Bundle bundle = new Bundle(); + bundle.putString("username", json.getString("username")); + bundle.putString("JSESSIONID", json.getString("JSESSIONID")); + init(bundle); + } + if (isExpanded()) { + Bundle bundle = new Bundle(); + bundle.putString("fullName", json.getString("fullName")); + bundle.putString("email", json.getString("email")); + setAdditionals(bundle); + } + } + + @Override + public int hashCode() { + return Objects.hashCode(username, JSESSIONID, fullName, email); + } +}