diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 2115831..ca1fede 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -2,28 +2,42 @@
+
-
+
+
+
+
+
+
+ android:theme="@style/FUTheme">
+
+
+ android:resource="@xml/provider_paths" />
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/de/sebse/fuplanner/MainActivity.java b/app/src/main/java/de/sebse/fuplanner/MainActivity.java
index 0a1ce48..21043a4 100644
--- a/app/src/main/java/de/sebse/fuplanner/MainActivity.java
+++ b/app/src/main/java/de/sebse/fuplanner/MainActivity.java
@@ -1,5 +1,6 @@
package de.sebse.fuplanner;
+import android.accounts.AccountManager;
import android.content.Intent;
import android.os.Bundle;
import android.view.Menu;
@@ -28,7 +29,6 @@ import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentTransaction;
import de.sebse.fuplanner.fragments.CanteensFragment;
-import de.sebse.fuplanner.fragments.LoginFragment;
import de.sebse.fuplanner.fragments.ModulesFragment;
import de.sebse.fuplanner.fragments.NewsFragment;
import de.sebse.fuplanner.fragments.PrefsFragment;
@@ -46,6 +46,8 @@ import de.sebse.fuplanner.services.KVV.KVVListener;
import de.sebse.fuplanner.services.KVV.types.LoginToken;
import de.sebse.fuplanner.services.KVV.types.Modules;
import de.sebse.fuplanner.services.News.NewsManager;
+import de.sebse.fuplanner.services.newkvv.AccountGeneral;
+import de.sebse.fuplanner.tools.CustomAccountManager;
import de.sebse.fuplanner.tools.MainActivityListener;
import de.sebse.fuplanner.tools.NewAsyncQueue;
import de.sebse.fuplanner.tools.Preferences;
@@ -67,7 +69,6 @@ public class MainActivity extends AppCompatActivity
private static final int FRAGMENT_STARTUP = 0;
private static final int FRAGMENT_MODULES = 1;
private static final int FRAGMENT_MODULES_DETAILS = 2;
- private static final int FRAGMENT_LOGIN = 3;
private static final int FRAGMENT_SCHEDULE = 4;
private static final int FRAGMENT_CANTEENS = 5;
private static final int FRAGMENT_CANTEENS_DETAILS = 6;
@@ -93,10 +94,14 @@ public class MainActivity extends AppCompatActivity
private boolean mOfflineBanner;
private final NewAsyncQueue mQueue = new NewAsyncQueue();
private long mDoubleBackToExitPressedOnce = 0;
+ private CustomAccountManager mAccountManager;
+ private boolean isPaused = false;
+ private boolean isLoggedInBeforePause = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
+ mAccountManager = new CustomAccountManager(AccountManager.get(this), () -> MainActivity.this);
int desiredPage = getDefaultFragmentAfterLogin();
String desiredData = "";
if (savedInstanceState != null) {
@@ -118,12 +123,53 @@ public class MainActivity extends AppCompatActivity
mNavigationView.setNavigationItemSelectedListener(this);
mFragmentManager = getSupportFragmentManager();
- if (!getKVV().account().restoreOnlineLogin()) {
- desiredPage = FRAGMENT_LOGIN;
+ //if (mAccountManager.getAccountsByType(AccountGeneral.ACCOUNT_TYPE).length == 0) {
+ if (!mAccountManager.hasAccounts(AccountGeneral.ACCOUNT_TYPE)) {
+ desiredPage = getDefaultFragmentAfterLogout();
desiredData = "";
+ mAccountManager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, null);
+ updateNavigation();
+ changeFragment(desiredPage, desiredData);
+ } else {
+ updateNavigation();
+ changeFragment(FRAGMENT_STARTUP);
+ int targetPage = desiredPage;
+ String targetData = desiredData;
+ getKVV().account().restoreOnlineLogin(isRestored -> {
+ updateNavigation();
+ if (isRestored)
+ changeFragment(targetPage, targetData);
+ else
+ changeFragment(getDefaultFragmentAfterLogout());
+ });
}
- updateNavigation();
- changeFragment(desiredPage, desiredData);
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+ isPaused = true;
+ isLoggedInBeforePause = getKVV().account().isLoggedIn();
+ log.d("onPause", isPaused, isLoggedInBeforePause);
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+ log.d("onResume", isPaused, isLoggedInBeforePause);
+ if (isPaused) {
+ getKVV().account().restoreOnlineLogin(isRestored -> {
+ log.d("onResume", isRestored);
+ updateNavigation();
+ if (isRestored && !isLoggedInBeforePause)
+ changeFragment(getDefaultFragmentAfterLogin());
+ else if (!isRestored && isLoggedInBeforePause) {
+ getKVV().account().logout(false);
+ changeFragment(getDefaultFragmentAfterLogout());
+ }
+ });
+ }
+ isPaused = false;
}
@Override
@@ -153,11 +199,10 @@ public class MainActivity extends AppCompatActivity
}
} else if (getKVV().account().isLoggedIn() && mFragmentPage != getDefaultFragmentAfterLogin()) {
changeFragment(getDefaultFragmentAfterLogin());
- } else if (!getKVV().account().isLoggedIn() && mFragmentPage != FRAGMENT_LOGIN) {
- changeFragment(FRAGMENT_LOGIN);
} else {
mDoubleBackToExitPressedOnce = System.currentTimeMillis();
showToast(R.string.back_to_exit);
+ //getTokenForAccountCreateIfNeeded(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV);
}
}
}
@@ -255,7 +300,7 @@ public class MainActivity extends AppCompatActivity
@Override
protected void onSaveInstanceState(Bundle savedInstanceState) {
- if (mFragmentPage != FRAGMENT_STARTUP && mFragmentPage != FRAGMENT_NONE && mFragmentPage != FRAGMENT_LOGIN) {
+ if (mFragmentPage != FRAGMENT_STARTUP && mFragmentPage != FRAGMENT_NONE) {
Fragment fragment = mFragmentManager.findFragmentByTag(String.valueOf(mFragmentPage));
savedInstanceState.putInt(ARG_FRAGMENT_PAGE, mFragmentPage);
if (fragment instanceof ModDetailFragment) {
@@ -312,11 +357,16 @@ public class MainActivity extends AppCompatActivity
return FRAGMENT_MODULES;
}
+ private int getDefaultFragmentAfterLogout() {
+ return FRAGMENT_CANTEENS;
+ }
+
private void toLogoutState() {
setOfflineBanner(false);
setRefreshFailedBanner(false);
updateNavigation();
- changeFragment(FRAGMENT_LOGIN);
+ changeFragment(getDefaultFragmentAfterLogout());
+ mAccountManager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, null);
}
private void toLoginState(String fullName, String email, int newFragment, boolean onlineMode) {
@@ -351,9 +401,9 @@ public class MainActivity extends AppCompatActivity
case FRAGMENT_MODULES:
fragment = ModulesFragment.newInstance();
break;
- case FRAGMENT_LOGIN:
+ /*case FRAGMENT_LOGIN:
fragment = LoginFragment.newInstance();
- break;
+ break;*/
case FRAGMENT_SCHEDULE:
fragment = ScheduleFragment.newInstance();
break;
@@ -475,7 +525,7 @@ public class MainActivity extends AppCompatActivity
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
- changeFragment(FRAGMENT_LOGIN);
+ mAccountManager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, null);
});
}
@@ -526,7 +576,7 @@ public class MainActivity extends AppCompatActivity
menuItem.setIcon(R.drawable.ic_sms_failed);
View view = View.inflate(this, R.layout.action_icon_number, null);
TextView v = view.findViewById(R.id.number);
- ((TextView) view.findViewById(R.id.number)).setText(String.format(Locale.getDefault(), "%d", i));
+ v.setText(String.format(Locale.getDefault(), "%d", i));
menuItem.setActionView(view);
}
if (++count[0] == MAX_COUNT) done.run();
@@ -560,6 +610,9 @@ public class MainActivity extends AppCompatActivity
+
+
+
@Override
public void onModulesFragmentInteraction(final String itemID) {
changeFragment(FRAGMENT_MODULES_DETAILS, itemID);
@@ -646,4 +699,9 @@ public class MainActivity extends AppCompatActivity
public void onKVVNetworkResponse(NetworkResponse error) {
setRefreshFailedBanner(error != null);
}
+
+ @Override
+ public CustomAccountManager getAccountManager() {
+ return mAccountManager;
+ }
}
diff --git a/app/src/main/java/de/sebse/fuplanner/fragments/LoginFragment.java b/app/src/main/java/de/sebse/fuplanner/fragments/LoginFragment.java
deleted file mode 100644
index a481e4f..0000000
--- a/app/src/main/java/de/sebse/fuplanner/fragments/LoginFragment.java
+++ /dev/null
@@ -1,112 +0,0 @@
-package de.sebse.fuplanner.fragments;
-
-import android.app.ProgressDialog;
-import android.content.Context;
-import android.os.Bundle;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.Button;
-import android.widget.EditText;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-import androidx.fragment.app.Fragment;
-import de.sebse.fuplanner.R;
-import de.sebse.fuplanner.tools.MainActivityListener;
-import de.sebse.fuplanner.tools.logging.Logger;
-
-/**
- * A simple {@link Fragment} subclass.
- * Use the {@link LoginFragment#newInstance} factory method to
- * create an instance of this fragment.
- */
-public class LoginFragment extends Fragment {
- private final Logger log = new Logger(this);
- @Nullable private MainActivityListener mActivityListener;
-
- public LoginFragment() {
- // Required empty public constructor
- }
-
- /**
- * Use this factory method to create a new instance of
- * this fragment using the provided parameters.
- *
- * @return A new instance of fragment LoginFragment.
- */
- public static LoginFragment newInstance() {
- LoginFragment fragment = new LoginFragment();
- Bundle args = new Bundle();
- fragment.setArguments(args);
- return fragment;
- }
-
- @Override
- public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- // Inflate the layout for this fragment
- View v = inflater.inflate(R.layout.fragment_login, container, false);
- if (mActivityListener != null && mActivityListener.getKVV().account().isOfflineStoredAvailable()) {
- Button offline_btn = v.findViewById(R.id.btn_offline);
- offline_btn.setVisibility(View.VISIBLE);
- offline_btn.setText(v.getResources().getString(R.string.enter_offline_mode, mActivityListener.getKVV().modules().list().getUsername()));
- offline_btn.setOnClickListener(v1 -> mActivityListener.getKVV().account().doOfflineLogin());
- }
-
- View btn_login = v.findViewById(R.id.btn_login);
- btn_login.setOnClickListener(view -> {
- final ProgressDialog progressDialog = new ProgressDialog(LoginFragment.this.getContext(),
- R.style.FUTheme_Dialog);
- progressDialog.setIndeterminate(true);
- progressDialog.setMessage("Authenticating...");
- progressDialog.show();
-
- EditText input_usr = ((View) view.getParent()).findViewById(R.id.input_username);
- EditText input_pwd = ((View) view.getParent()).findViewById(R.id.input_password);
-
- String username = input_usr.getText().toString();
- String password = input_pwd.getText().toString();
-
- mActivityListener.getKVV().account().doOnlineLogin(username, password, success -> {
- progressDialog.dismiss();
- mActivityListener.getGoogleAuth().setLoginState(username, password);
- input_usr.setError(null);
- input_pwd.setError(null);
- }, error -> {
- progressDialog.dismiss();
- // Invalid password
- if (mActivityListener != null) {
- if (error.getCode() == 100131) {
- mActivityListener.showToast(R.string.invalid_credentials);
- input_usr.setError(input_usr.getResources().getString(R.string.invalid_credentials));
- input_pwd.setError(input_pwd.getResources().getString(R.string.invalid_credentials));
- } else {
- mActivityListener.showToast(v.getResources().getString(R.string.error_occurred_code, error.getCode()));
- }
- }
- log.e("Error on KVV login!", error);
- });
- });
-
- return v;
- }
-
-
-
- @Override
- public void onAttach(Context context) {
- super.onAttach(context);
- if (context instanceof MainActivityListener) {
- mActivityListener = (MainActivityListener) context;
- mActivityListener.onTitleTextChange(R.string.log_in);
- } else
- throw new RuntimeException(context.toString() + " must implement MainActivityListener");
- }
-
- @Override
- public void onDetach() {
- super.onDetach();
- mActivityListener = null;
- }
-}
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 402899f..9747f7f 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
@@ -4,6 +4,7 @@ import com.android.volley.NetworkResponse;
import de.sebse.fuplanner.services.GoogleAuth.Credentials;
import de.sebse.fuplanner.services.KVV.types.LoginToken;
+import de.sebse.fuplanner.tools.CustomAccountManager;
import de.sebse.fuplanner.tools.network.NetworkCallback;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;
@@ -17,4 +18,6 @@ public interface KVVListener {
void onModuleListChange();
void onKVVNetworkResponse(NetworkResponse error);
+
+ CustomAccountManager getAccountManager();
}
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 70c2c92..ca47f2e 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
@@ -2,19 +2,14 @@ package de.sebse.fuplanner.services.KVV;
import android.content.Context;
-
import org.jetbrains.annotations.NotNull;
import org.json.JSONException;
import org.json.JSONObject;
-import java.io.FileNotFoundException;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
import androidx.annotation.Nullable;
import de.sebse.fuplanner.services.KVV.types.LoginToken;
+import de.sebse.fuplanner.services.newkvv.AccountGeneral;
+import de.sebse.fuplanner.tools.CustomAccountManager;
import de.sebse.fuplanner.tools.NetworkCallbackCollector;
import de.sebse.fuplanner.tools.network.HTTPService;
import de.sebse.fuplanner.tools.network.NetworkCallback;
@@ -33,63 +28,43 @@ public class Login extends HTTPService {
this.mListener = listener;
}
+ @Deprecated
+ public void reset() {
+ mToken = null;
+ mLoginPending = false;
+ mOnlineMode = false;
+ }
+
public void doOnlineLogin(@NotNull String username, @NotNull String password, NetworkCallback callback, NetworkErrorCallback errorCallback) {
+
+ }
+
+ //public boolean restoreOnlineLogin() {
+ // return restoreLogin(true);
+ //}
+
+ //public boolean doOfflineLogin() {
+ // return restoreLogin(false);
+ //}
+
+ public void restoreOnlineLogin(BooleanInterface callback) {
if (mLoginPending) {
- errorCallback.onError(new NetworkError(100160, -1, "Login already pending!"));
- log.t();
+ callback.run(false);
+ return;
}
mLoginPending = true;
- doLogin(username, password, token -> {
- testLoginToken(token, token2 -> {
- setToken(token2, true);
- mLoginPending = false;
- callback.onResponse(token2);
- }, error -> {
- mLoginPending = false;
- errorCallback.onError(error);
- });
- }, error -> {
+ LoginToken.load(mListener.getAccountManager(), token -> {
+ boolean result = setToken(token, true);
mLoginPending = false;
- errorCallback.onError(error);
+ log.d("loginToken", token != null ? token.toString() : null);
+ callback.run(result);
});
}
- public boolean restoreOnlineLogin() {
- return restoreLogin(true);
- }
-
- public boolean doOfflineLogin() {
- return restoreLogin(false);
- }
-
- private boolean restoreLogin(boolean enteringOnlineMode) {
- if (mLoginPending || mToken != null)
- return false;
- mLoginPending = true;
- boolean result = false;
- try {
- result = setToken(LoginToken.load(getContext()), enteringOnlineMode);
- } catch (FileNotFoundException ignored) {
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- mLoginPending = false;
- return result;
- }
-
- public boolean isOfflineStoredAvailable() {
- try {
- LoginToken load = LoginToken.load(getContext());
- return load != null;
- } catch (FileNotFoundException ignored) {
- } catch (IOException e) {
- e.printStackTrace();
- } catch (ClassNotFoundException e) {
- e.printStackTrace();
- }
- return false;
+ public void isOfflineStoredAvailable(BooleanInterface callback) {
+ LoginToken.load(mListener.getAccountManager(), token -> {
+ callback.run(token != null);
+ });
}
public boolean logout(boolean delete) {
@@ -98,7 +73,7 @@ public class Login extends HTTPService {
if (mToken == null)
return true;
if (delete)
- mToken.delete(getContext());
+ mToken.delete(mListener.getAccountManager());
mToken = null;
return handleCallbacks();
}
@@ -155,14 +130,27 @@ public class Login extends HTTPService {
mRefreshCallbacks.add(success, error);
if (!isFirst)
return;
- mListener.getCredentials(credentials -> {
+ CustomAccountManager manager = mListener.getAccountManager();
+ manager.doInvalidateToken(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, ignored -> {
+ log.d("try restore", ignored);
+ restoreOnlineLogin(isRestored -> {
+ log.d("restore", isRestored, mToken);
+ if (isRestored)
+ testLoginToken(mRefreshCallbacks::responseResponse, mRefreshCallbacks::responseError);
+ else {
+ logout(true);
+ mRefreshCallbacks.responseError(new NetworkError(100180, 403, "Re-login failed!"));
+ }
+ });
+ });
+ /* mListener.getCredentials(credentials -> {
doOnlineLogin(credentials.getUsername(), credentials.getPassword(),
mRefreshCallbacks::responseResponse,
mRefreshCallbacks::responseError);
}, e -> {
logout(false);
mRefreshCallbacks.responseError(e);
- });
+ });*/
}
@@ -182,272 +170,11 @@ public class Login extends HTTPService {
return false;
boolean isOnlyRefresh = mToken != null;
mToken = token;
- if (enteringOnlineMode) {
- try {
- mToken.save(getContext());
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
mOnlineMode = enteringOnlineMode;
return isOnlyRefresh || handleCallbacks();
}
-
-
-
-
-
-
-
-
-
- private void doLogin(String username, String password, NetworkCallback callback, NetworkErrorCallback error) {
- startKVVSession(success -> {
- String kvvJSESSIONID = success.get("JSESSIONID");
- getSAMLRequest(kvvJSESSIONID, success1 -> startIdentSession(success1.get("Location"), success11 -> {
- String identJSESSIONID = success11.get("JSESSIONID");
- String ident_idp_authn_lc_key = success11.get("_idp_authn_lc_key");
- String identROUTEID = success11.get("ROUTEID");
- loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success111 -> loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success11112 -> {
- String ident_idp_session = success11112.get("_idp_session");
- getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, success1111 -> loginKVV(success1111.get("RelayState"), success1111.get("SAMLResponse"), kvvJSESSIONID, success111112 -> {
- LoginToken token = new LoginToken(username, success111112.get("shibsessionKey"), success111112.get("shibsessionName"), kvvJSESSIONID);
- finishKVVlogin(token, success11111 -> callback.onResponse(token), error);
- }, error), error);
- }, error), error);
- }, error), error);
- }, error);
- }
-
- /*
- GET https://kvv.imp.fu-berlin.de/portal/login
- -> JSESSIONID 5c10406f-588c-4c16-96e9-c80d115417de.tomcat1
- */
- private void startKVVSession(final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
- get("https://kvv.imp.fu-berlin.de/portal/login", null, response -> {
- String cookies = response.getHeaders().get("Set-Cookie");
- if (cookies==null) {
- errorCallback.onError(new NetworkError(100101, -1, "Error on starting KVV session!"));
- return;
- }
- HashMap object;
- try {
- object = getCookie(cookies, new String[]{"JSESSIONID"});
- } catch (NoSuchFieldException e) {
- errorCallback.onError(new NetworkError(100102, -1, "Error on starting KVV session!"));
- return;
- }
- callback.onResponse(object);
- }, error -> errorCallback.onError(new NetworkError(100100, error.networkResponse.statusCode, "Error on starting KVV session!")));
- }
-
- /*
- GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
- <- JSESSIONID
- -> (Location-Header) https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
- ?SAMLRequest=fZLLb.....Q8yre3X1IHwkJKE0Mnpy/V9TH4A
- &RelayState=ss:mem:7ea01e29157b8bd906f7002176.....0d1a505f2c8bf
- */
- private void getSAMLRequest(String JSESSIONID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
- HashMap cookies = new HashMap<>();
- cookies.put("JSESSIONID", JSESSIONID);
- get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", cookies, 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!")));
- }
-
- /*
- GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
- ?SAMLRequest=fZLLbsIwEEV/JfI+cWJAUIsgpbAoEi2IpF10UznxUKw6dupxaPn7hkdb2LD29bkzRzNGUeuGZ63fmjV8toA++K61QX58SEnrDLcCFXIjakDuK55njwvOopg3znpbWU2CDBGcV9ZMrcG2BpeD26kKnteLlGy9b5BT+rHbRapuok0bluC0MpEEmm9VWVoNfhshWnpgM7pa5gUJZt0wyogD9h+iJBiv/P6aomQTbtqSdhNtlIYzZg1SOag8zfMlCeazlLyNqpHsy1gO2V1fVsNBMuqJoUyAJaxXDUaiiyG2MDfohfEpYXEyDJM4ZKxgCe/FPI5fSbA6L36vjFTm/bal8hRC/lAUq/C02gs4PK7VBchkfHDNj8Xuwv5trPhVTiY3BeOf4DG96DmVNvypA89nK6tVtQ8yre3X1IHwkJKE0Mnpy/V9TH4A
- &RelayState=ss:mem:7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
- -> JSESSIONID C4B6A428BA1F50746235D03F5D107A57
- -> _idp_authn_lc_key 57a6ae26067f374cc3d0ccfc47e27b04b47752d2a3d4eb2782af0d3994535395
- -> ROUTEID .1
- */
- private void startIdentSession(String url, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
- get(url, null, response -> {
- String cookies = response.getHeaders().get("Set-Cookie");
- if (cookies==null) {
- errorCallback.onError(new NetworkError(100121, -1, "Error on starting Ident session!"));
- return;
- }
- HashMap object;
- try {
- object = getCookie(cookies, new String[]{"JSESSIONID", "_idp_authn_lc_key", "ROUTEID"});
- } catch (NoSuchFieldException e) {
- errorCallback.onError(new NetworkError(100122, -1, "Error on starting Ident session!"));
- return;
- }
- callback.onResponse(object);
- }, error -> errorCallback.onError(new NetworkError(100120, error.networkResponse.statusCode, "Error on starting Ident session!")));
- }
-
- /*
- POST https://identity.fu-berlin.de/idp-fub/Authn/UserPassword
- <- j_username seedorf96
- <- j_password neinhieristpatrick
- <- (Header-"Content-Type") application/x-www-form-urlencoded
- <- JSESSIONID
- <- _idp_authn_lc_key
- <- ROUTEID
- -> _idp_session OTMuMTkzLjg1LjMz|LQ==|OGYxOWI4MjA2NTQ4YWUwYzJkOWM4Mjk4YzcwZDMwZmJiZjBmMTdmMzkyZGU2OWIwY2JkNmZlNjlmNTRmNzBlMQ==|wLlzQal7VqyntmG2vLNn06wt8wQ=
- */
- private void loginIdent(final boolean first, String username, String password, String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
- HashMap cookies = new HashMap<>();
- cookies.put("JSESSIONID", JSESSIONID);
- cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
- cookies.put("ROUTEID", ROUTEID);
- HashMap body = new HashMap<>();
- body.put("j_username", username);
- body.put("j_password", password);
- post("https://identity.fu-berlin.de/idp-fub/Authn/UserPassword", cookies, body, response -> {
- if (first) {
- callback.onResponse(new HashMap<>());
- return;
- }
-
- String cookies1 = response.getHeaders().get("Set-Cookie");
- if (cookies1 ==null) {
- errorCallback.onError(new NetworkError(100131, -1, "Error on logging in to Identity Server!"));
- return;
- }
- HashMap object;
- try {
- object = getCookie(cookies1, new String[]{"_idp_session"});
- } catch (NoSuchFieldException e) {
- errorCallback.onError(new NetworkError(100132, -1, "Error on logging in to Identity Server!"));
- return;
- }
- callback.onResponse(object);
- }, error -> errorCallback.onError(new NetworkError(100130, error.networkResponse.statusCode, "Error on logging in to Identity Server!")));
- }
-
- /*
- GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
- <- JSESSIONID
- <- _idp_authn_lc_key
- <- ROUTEID
- <- _idp_session
- -> (BODY) RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
- -> (BODY) SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
- */
- private void getSAMLResponse(String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, String _idp_session, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
- HashMap cookies = new HashMap<>();
- cookies.put("JSESSIONID", JSESSIONID);
- cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
- cookies.put("ROUTEID", ROUTEID);
- cookies.put("_idp_session", _idp_session);
- get("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO", cookies, response -> {
- String body = response.getParsed();
- if (body == null) {
- errorCallback.onError(new NetworkError(100143, -1, "Error on getting SAML response!"));
- return;
- }
-
- HashMap object = new HashMap<>();
-
- Pattern pattern = Pattern.compile("ss:mem:([0-9a-f]+)");
- Matcher matcher = pattern.matcher(body);
- if (!matcher.find()) {
- errorCallback.onError(new NetworkError(100142, -1, "Error on getting SAML response!"));
- return;
- }
- object.put("RelayState", "ss:mem:"+matcher.group(1));
-
- pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)");
- matcher = pattern.matcher(body);
- if (!matcher.find()) {
- errorCallback.onError(new NetworkError(100141, -1, "Error on getting SAML response!"));
- return;
- }
- object.put("SAMLResponse", matcher.group(1));
-
- callback.onResponse(object);
- }, error -> errorCallback.onError(new NetworkError(100140, error.networkResponse.statusCode, "Error on getting SAML response!")));
- }
-
-
- /*
- POST https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST
- <- RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
- <- SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
- <- JSESSIONID
- -> _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
- _b1912c5a03d733a80bd3fee772bf68d4
- */
- private void loginKVV(String RelayState, String SAMLResponse, String JSESSIONID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
- HashMap cookies = new HashMap<>();
- cookies.put("JSESSIONID", JSESSIONID);
- HashMap body = new HashMap<>();
- body.put("RelayState", RelayState);
- body.put("SAMLResponse", SAMLResponse);
- post("https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST", cookies, body, response -> {
- String cookies1 = response.getHeaders().get("Set-Cookie");
- if (cookies1 ==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(cookies1);
- if (!matcher.find()) {
- errorCallback.onError(new NetworkError(100152, -1, "Error on starting Ident 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 Ident session!")));
- }
-
-
- /*
- GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
- <- JSESSIONID
- <- _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
- _b1912c5a03d733a80bd3fee772bf68d4
- */
- private void finishKVVlogin(LoginToken loginToken, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
- get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", loginToken.getCookies(), response -> callback.onResponse(new HashMap<>()), error -> errorCallback.onError(new NetworkError(100160, error.networkResponse.statusCode, "Cannot finish login process!")));
- }
-
-
-
-
-
-
-
-
-
-
-
-
- private String getCookie(String cookies, String name) throws NoSuchFieldException {
- Pattern pattern = Pattern.compile(name+"=([^;]+);");
- Matcher matcher = pattern.matcher(cookies);
- if (!matcher.find()) {
- log.e("GETcookie failed", name);
- log.e("GETcookie failed", cookies);
- throw new NoSuchFieldException();
- }
- return matcher.group(1);
- }
-
- private HashMap getCookie(String cookies, String[] names) throws NoSuchFieldException {
- HashMap result = new HashMap<>();
- for (String name: names) {
- result.put(name,this.getCookie(cookies, name));
- }
- return result;
+ public interface BooleanInterface {
+ void run(boolean bool);
}
}
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
index 0657069..544729f 100644
--- 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
@@ -2,23 +2,25 @@ package de.sebse.fuplanner.services.KVV.types;
import android.content.Context;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
+import org.json.JSONException;
+import org.json.JSONObject;
+
import java.io.IOException;
-import java.io.ObjectInputStream;
-import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import de.sebse.fuplanner.services.newkvv.AccountGeneral;
+import de.sebse.fuplanner.tools.CustomAccountManager;
+import de.sebse.fuplanner.tools.logging.Logger;
/**
* Created by sebastian on 29.10.17.
*/
public class LoginToken implements Serializable {
+ static Logger log = new Logger("LoginToken");
private static final String FILE_NAME = "LoginTokenSaving";
private final String username;
@@ -36,33 +38,35 @@ public class LoginToken implements Serializable {
}
@Nullable
- public static LoginToken load(Context context) throws IOException, ClassNotFoundException {
- FileInputStream fis;
- try {
- fis = context.openFileInput(FILE_NAME);
- } catch (FileNotFoundException e) {
- return null;
+ public static void load(CustomAccountManager manager, LoginTokenInterface callback) {
+ log.d("try to login");
+ if (!manager.hasAccounts(AccountGeneral.ACCOUNT_TYPE)) {
+ callback.run(null);
+ return;
}
- ObjectInputStream is = new ObjectInputStream(fis);
- Object readObject = is.readObject();
- if (!(readObject instanceof LoginToken))
- return null;
- LoginToken loginToken = (LoginToken) readObject;
- is.close();
- fis.close();
- return loginToken;
+ log.d("has accounts");
+ manager.getTokenByType(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV, tokenString -> {
+ //manager.getTokenByTypeSync(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV);
+ if (tokenString == null) {
+ callback.run(null);
+ return;
+ }
+ log.d("got token string", tokenString);
+ callback.run(LoginToken.fromJsonString(tokenString));
+ //return LoginToken.fromJsonString(tokenString);
+ });
}
public void save(Context context) throws IOException {
- FileOutputStream fos = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
+ /*FileOutputStream fos = context.openFileOutput(FILE_NAME, Context.MODE_PRIVATE);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.close();
- fos.close();
+ fos.close();*/
}
- public void delete(Context context) {
- context.deleteFile(FILE_NAME);
+ public void delete(CustomAccountManager manager) {
+ manager.deleteAccount(AccountGeneral.ACCOUNT_TYPE);
}
public void setAdditionals(String fullName, String email) {
@@ -118,4 +122,43 @@ public class LoginToken implements Serializable {
}
return result.substring(0, result.length()-1);
}
+
+ public String toJsonString() {
+ JSONObject json = new JSONObject();
+ try {
+ json.put("username", username);
+ json.put("shibsessionKey", shibsessionKey);
+ json.put("shibsessionName", shibsessionName);
+ json.put("JSESSIONID", JSESSIONID);
+ json.put("fullName", fullName);
+ json.put("email", email);
+ } catch (JSONException e) {
+ return null;
+ }
+ return json.toString();
+ }
+
+ public static LoginToken fromJsonString(String tokenString) {
+ try {
+ JSONObject json = new JSONObject(tokenString);
+ LoginToken token = new LoginToken(
+ json.getString("username"),
+ json.getString("shibsessionName"),
+ json.getString("shibsessionName"),
+ json.getString("JSESSIONID"));
+ if (!json.isNull("fullName"))
+ token.setAdditionals(
+ json.getString("fullName"),
+ json.getString("email")
+ );
+ return token;
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ public interface LoginTokenInterface {
+ void run(LoginToken token);
+ }
}
diff --git a/app/src/main/java/de/sebse/fuplanner/services/newkvv/AccountGeneral.java b/app/src/main/java/de/sebse/fuplanner/services/newkvv/AccountGeneral.java
new file mode 100644
index 0000000..2d98253
--- /dev/null
+++ b/app/src/main/java/de/sebse/fuplanner/services/newkvv/AccountGeneral.java
@@ -0,0 +1,7 @@
+package de.sebse.fuplanner.services.newkvv;
+
+public class AccountGeneral {
+ public static final String ACCOUNT_TYPE = "de.sebse.fuplanner.fuauth";
+ public static final String AUTHTOKEN_TYPE_KVV = "KVV";
+ public static final String AUTHTOKEN_TYPE_BLACKBOARD = "Blackboard";
+}
diff --git a/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticator.java b/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticator.java
new file mode 100644
index 0000000..6dfba9c
--- /dev/null
+++ b/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticator.java
@@ -0,0 +1,104 @@
+package de.sebse.fuplanner.services.newkvv;
+
+import android.accounts.AbstractAccountAuthenticator;
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorResponse;
+import android.accounts.AccountManager;
+import android.accounts.NetworkErrorException;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+
+import java.util.concurrent.ExecutionException;
+
+public class FUAuthenticator extends AbstractAccountAuthenticator {
+
+ private final Context mContext;
+
+ public FUAuthenticator(Context context) {
+ super(context);
+ this.mContext = context;
+ }
+
+ @Override
+ public Bundle editProperties(AccountAuthenticatorResponse accountAuthenticatorResponse, String s) {
+ return null;
+ }
+
+ @Override
+ public Bundle addAccount(AccountAuthenticatorResponse response, String accountType, String authTokenType, String[] requiredFeatures, Bundle options) throws NetworkErrorException {
+ final Intent intent = new Intent(mContext, FUAuthenticatorActivity.class);
+ intent.putExtra(FUAuthenticatorActivity.ARG_ACCOUNT_TYPE, accountType);
+ intent.putExtra(FUAuthenticatorActivity.ARG_AUTH_TYPE, authTokenType);
+ intent.putExtra(FUAuthenticatorActivity.ARG_IS_ADDING_NEW_ACCOUNT, true);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+ return bundle;
+ }
+
+ @Override
+ public Bundle confirmCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, Bundle bundle) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle getAuthToken(AccountAuthenticatorResponse response, Account account, String authTokenType, Bundle options) throws NetworkErrorException {
+
+ // Extract the username and password from the Account Manager, and ask
+ // the server for an appropriate AuthToken.
+ final AccountManager am = AccountManager.get(mContext);
+
+ String authToken = am.peekAuthToken(account, authTokenType);
+
+ // Lets give another try to authenticate the user
+ if (TextUtils.isEmpty(authToken)) {
+ final String password = am.getPassword(account);
+ if (password != null) {
+ try {
+ authToken = new UserLoginTask(account.name, password, authTokenType, mContext).execute((Void) null).get();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ // If we get an authToken - we return it
+ if (!TextUtils.isEmpty(authToken)) {
+ final Bundle result = new Bundle();
+ result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
+ result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
+ result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
+ return result;
+ }
+
+ // If we get here, then we couldn't access the user's password - so we
+ // need to re-prompt them for their credentials. We do that by creating
+ // an intent to display our AuthenticatorActivity.
+ final Intent intent = new Intent(mContext, FUAuthenticatorActivity.class);
+ intent.putExtra(AccountManager.KEY_ACCOUNT_AUTHENTICATOR_RESPONSE, response);
+ intent.putExtra(FUAuthenticatorActivity.ARG_ACCOUNT_TYPE, account.type);
+ intent.putExtra(FUAuthenticatorActivity.ARG_AUTH_TYPE, authTokenType);
+ final Bundle bundle = new Bundle();
+ bundle.putParcelable(AccountManager.KEY_INTENT, intent);
+ return bundle;
+ }
+
+ @Override
+ public String getAuthTokenLabel(String s) {
+ return null;
+ }
+
+ @Override
+ public Bundle updateCredentials(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String s, Bundle bundle) throws NetworkErrorException {
+ return null;
+ }
+
+ @Override
+ public Bundle hasFeatures(AccountAuthenticatorResponse accountAuthenticatorResponse, Account account, String[] strings) throws NetworkErrorException {
+ return null;
+ }
+}
diff --git a/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticatorActivity.java b/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticatorActivity.java
new file mode 100644
index 0000000..03ee6cd
--- /dev/null
+++ b/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticatorActivity.java
@@ -0,0 +1,290 @@
+package de.sebse.fuplanner.services.newkvv;
+
+import android.accounts.Account;
+import android.accounts.AccountAuthenticatorActivity;
+import android.accounts.AccountManager;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.annotation.TargetApi;
+import android.app.LoaderManager.LoaderCallbacks;
+import android.content.Context;
+import android.content.CursorLoader;
+import android.content.Intent;
+import android.content.Loader;
+import android.content.pm.PackageManager;
+import android.database.Cursor;
+import android.net.Uri;
+import android.os.Build;
+import android.os.Bundle;
+import android.provider.ContactsContract;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.Button;
+import android.widget.EditText;
+
+import androidx.annotation.NonNull;
+import de.sebse.fuplanner.R;
+
+import static de.sebse.fuplanner.services.newkvv.UserLoginTask.PARAM_USER_PASS;
+
+/**
+ * A login screen that offers login via email/password.
+ */
+public class FUAuthenticatorActivity extends AccountAuthenticatorActivity implements LoaderCallbacks {
+
+ /**
+ * Id to identity READ_CONTACTS permission request.
+ */
+ private static final int REQUEST_READ_CONTACTS = 0;
+
+ /**
+ * Keep track of the login task to ensure we can cancel it if requested.
+ */
+ UserLoginTask mAuthTask = null;
+
+ // UI references.
+ private EditText mEmailView;
+ EditText mPasswordView;
+ private View mProgressView;
+ private View mLoginFormView;
+
+
+
+ public static final String ARG_ACCOUNT_TYPE = "ARG_ACCOUNT_TYPE";
+ public static final String ARG_AUTH_TYPE = "ARG_AUTH_TYPE";
+ public static final String ARG_IS_ADDING_NEW_ACCOUNT = "ARG_IS_ADDING_NEW_ACCOUNT";
+ private String mAccountType;
+ private String mAuthTokenType;
+ private boolean mIsAddingNewAccount;
+
+
+ @Override
+ protected void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ mAccountType = getIntent().getStringExtra(ARG_ACCOUNT_TYPE);
+ mAuthTokenType = getIntent().getStringExtra(ARG_AUTH_TYPE);
+ mIsAddingNewAccount = getIntent().getBooleanExtra(ARG_IS_ADDING_NEW_ACCOUNT, false);
+
+ setContentView(R.layout.activity_fu_authenticator);
+ // Set up the login form.
+ mEmailView = findViewById(R.id.input_username);
+ populateAutoComplete();
+
+ mPasswordView = findViewById(R.id.input_password);
+ mPasswordView.setOnEditorActionListener((textView, id, keyEvent) -> {
+ if (id == EditorInfo.IME_ACTION_DONE || id == EditorInfo.IME_NULL) {
+ attemptLogin();
+ return true;
+ }
+ return false;
+ });
+
+ Button mEmailSignInButton = findViewById(R.id.btn_login);
+ mEmailSignInButton.setOnClickListener(view -> attemptLogin());
+
+ mLoginFormView = findViewById(R.id.login_form);
+ mProgressView = findViewById(R.id.login_progress);
+ }
+
+ private void populateAutoComplete() {
+ if (!mayRequestContacts()) {
+ return;
+ }
+
+ getLoaderManager().initLoader(0, null, this);
+ }
+
+ private boolean mayRequestContacts() {
+ /*if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
+ return true;
+ }
+ if (checkSelfPermission(READ_CONTACTS) == PackageManager.PERMISSION_GRANTED) {
+ return true;
+ }
+ if (shouldShowRequestPermissionRationale(READ_CONTACTS)) {
+ Snackbar.make(mEmailView, R.string.permission_rationale, Snackbar.LENGTH_INDEFINITE)
+ .setAction(android.R.string.ok, new View.OnClickListener() {
+ @Override
+ @TargetApi(Build.VERSION_CODES.M)
+ public void onClick(View v) {
+ requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
+ }
+ });
+ } else {
+ requestPermissions(new String[]{READ_CONTACTS}, REQUEST_READ_CONTACTS);
+ }*/
+ return false;
+ }
+
+ /**
+ * Callback received when a permissions request has been completed.
+ */
+ @Override
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions,
+ @NonNull int[] grantResults) {
+ if (requestCode == REQUEST_READ_CONTACTS) {
+ if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
+ populateAutoComplete();
+ }
+ }
+ }
+
+
+ /**
+ * Attempts to sign in or register the account specified by the login form.
+ * If there are form errors (invalid email, missing fields, etc.), the
+ * errors are presented and no actual login attempt is made.
+ */
+ private void attemptLogin() {
+ InputMethodManager inputManager = (InputMethodManager) this.getSystemService(Context.INPUT_METHOD_SERVICE);
+ if (inputManager != null && getCurrentFocus() != null)
+ inputManager.hideSoftInputFromWindow(this.getCurrentFocus().getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
+ if (mAuthTask != null) {
+ return;
+ }
+
+ // Reset errors.
+ mEmailView.setError(null);
+ mPasswordView.setError(null);
+
+ // Store values at the time of the login attempt.
+ String email = mEmailView.getText().toString();
+ String password = mPasswordView.getText().toString();
+
+ boolean cancel = false;
+ View focusView = null;
+
+ // Check for a valid password, if the user entered one.
+ if (!TextUtils.isEmpty(password) && !isPasswordValid(password)) {
+ mPasswordView.setError(getString(R.string.error_invalid_password));
+ focusView = mPasswordView;
+ cancel = true;
+ }
+
+ // Check for a valid email address.
+ if (TextUtils.isEmpty(email)) {
+ mEmailView.setError(getString(R.string.error_field_required));
+ focusView = mEmailView;
+ cancel = true;
+ } else if (!isEmailValid(email)) {
+ mEmailView.setError(getString(R.string.error_invalid_email));
+ focusView = mEmailView;
+ cancel = true;
+ }
+
+ if (cancel) {
+ // There was an error; don't attempt login and focus the first
+ // form field with an error.
+ focusView.requestFocus();
+ } else {
+ // Show a progress spinner, and kick off a background task to
+ // perform the user login attempt.
+ showProgress(true);
+ mAuthTask = new UserLoginTask(email, password, mAuthTokenType, this);
+ mAuthTask.execute((Void) null);
+ }
+ }
+
+ private boolean isEmailValid(String email) {
+ //TODO: Replace this with your own logic
+ return true;//email.contains("@");
+ }
+
+ private boolean isPasswordValid(String password) {
+ //TODO: Replace this with your own logic
+ return password.length() > 4;
+ }
+
+ /**
+ * Shows the progress UI and hides the login form.
+ */
+ @TargetApi(Build.VERSION_CODES.HONEYCOMB_MR2)
+ void showProgress(final boolean show) {
+ // On Honeycomb MR2 we have the ViewPropertyAnimator APIs, which allow
+ // for very easy animations. If available, use these APIs to fade-in
+ // the progress spinner.
+ int shortAnimTime = getResources().getInteger(android.R.integer.config_shortAnimTime);
+
+ mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
+ mLoginFormView.animate().setDuration(shortAnimTime).alpha(
+ show ? 0 : 1).setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mLoginFormView.setVisibility(show ? View.GONE : View.VISIBLE);
+ }
+ });
+
+ mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
+ mProgressView.animate().setDuration(shortAnimTime).alpha(
+ show ? 1 : 0).setListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mProgressView.setVisibility(show ? View.VISIBLE : View.GONE);
+ }
+ });
+ }
+
+ @Override
+ public Loader onCreateLoader(int i, Bundle bundle) {
+ return new CursorLoader(this,
+ // Retrieve data rows for the device user's 'profile' contact.
+ Uri.withAppendedPath(ContactsContract.Profile.CONTENT_URI,
+ ContactsContract.Contacts.Data.CONTENT_DIRECTORY), ProfileQuery.PROJECTION,
+
+ // Select only email addresses.
+ ContactsContract.Contacts.Data.MIMETYPE +
+ " = ?", new String[]{ContactsContract.CommonDataKinds.Email
+ .CONTENT_ITEM_TYPE},
+
+ // Show primary email addresses first. Note that there won't be
+ // a primary email address if the user hasn't specified one.
+ ContactsContract.Contacts.Data.IS_PRIMARY + " DESC");
+ }
+
+ @Override
+ public void onLoadFinished(Loader cursorLoader, Cursor cursor) {
+ }
+
+ @Override
+ public void onLoaderReset(Loader cursorLoader) {
+
+ }
+
+
+ private interface ProfileQuery {
+ String[] PROJECTION = {
+ ContactsContract.CommonDataKinds.Email.ADDRESS,
+ ContactsContract.CommonDataKinds.Email.IS_PRIMARY,
+ };
+
+ int ADDRESS = 0;
+ int IS_PRIMARY = 1;
+ }
+
+ void finishLogin(Intent intent) {
+ String accountName = intent.getStringExtra(AccountManager.KEY_ACCOUNT_NAME);
+ String accountPassword = intent.getStringExtra(PARAM_USER_PASS);
+ final Account account = new Account(accountName, intent.getStringExtra(AccountManager.KEY_ACCOUNT_TYPE));
+ final AccountManager mAccountManager = AccountManager.get(this);
+
+ if (getIntent().getBooleanExtra(ARG_IS_ADDING_NEW_ACCOUNT, false)) {
+ String authtoken = intent.getStringExtra(AccountManager.KEY_AUTHTOKEN);
+ String authtokenType = mAuthTokenType;
+
+ // Creating the account on the device and setting the auth token we got
+ // (Not setting the auth token will cause another call to the server to authenticate the user)
+ mAccountManager.addAccountExplicitly(account, accountPassword, null);
+ mAccountManager.setAuthToken(account, authtokenType, authtoken);
+ } else {
+ mAccountManager.setPassword(account, accountPassword);
+ }
+
+ setAccountAuthenticatorResult(intent.getExtras());
+ setResult(RESULT_OK, intent);
+ finish();
+ }
+}
+
diff --git a/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticatorService.java b/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticatorService.java
new file mode 100644
index 0000000..a6f1516
--- /dev/null
+++ b/app/src/main/java/de/sebse/fuplanner/services/newkvv/FUAuthenticatorService.java
@@ -0,0 +1,13 @@
+package de.sebse.fuplanner.services.newkvv;
+
+import android.app.Service;
+import android.content.Intent;
+import android.os.IBinder;
+
+public class FUAuthenticatorService extends Service {
+ @Override
+ public IBinder onBind(Intent intent) {
+ FUAuthenticator authenticator = new FUAuthenticator(this);
+ return authenticator.getIBinder();
+ }
+}
diff --git a/app/src/main/java/de/sebse/fuplanner/services/newkvv/UserLoginTask.java b/app/src/main/java/de/sebse/fuplanner/services/newkvv/UserLoginTask.java
new file mode 100644
index 0000000..3338106
--- /dev/null
+++ b/app/src/main/java/de/sebse/fuplanner/services/newkvv/UserLoginTask.java
@@ -0,0 +1,124 @@
+package de.sebse.fuplanner.services.newkvv;
+
+import android.accounts.AccountManager;
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.os.AsyncTask;
+import android.os.Build;
+
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicReference;
+
+import androidx.annotation.Nullable;
+import de.sebse.fuplanner.R;
+import de.sebse.fuplanner.services.KVV.types.LoginToken;
+import de.sebse.fuplanner.services.newkvv.network.Login;
+import de.sebse.fuplanner.tools.logging.Logger;
+
+
+/**
+ * Represents an asynchronous login/registration task used to authenticate
+ * the user.
+ */
+public class UserLoginTask extends AsyncTask {
+
+ /**
+ * A dummy authentication store containing known user names and passwords.
+ * TODO: remove after connecting to a real authentication system.
+ */
+ /*private static final String[] DUMMY_CREDENTIALS = new String[]{
+ "foo@example.com:hello", "bar@example.com:world"
+ };*/
+ static final String PARAM_USER_PASS = "PARAM_USER_PASS";
+
+ private final String mEmail;
+ private final String mPassword;
+ private final Login mVolleyLogin;
+ private String mTokenType;
+ private Logger log = new Logger(this);
+ @SuppressLint("StaticFieldLeak")
+ @Nullable
+ private FUAuthenticatorActivity mActivity;
+
+ UserLoginTask(String email, String password, String tokenType, @NotNull Context context) {
+ mEmail = email;
+ mPassword = password;
+ mTokenType = tokenType;
+ mVolleyLogin = new Login(context);
+ if (context instanceof FUAuthenticatorActivity)
+ mActivity = (FUAuthenticatorActivity) context;
+ }
+
+ @Override
+ protected String doInBackground(Void... params) {
+ // TODO: attempt authentication against a network service.
+
+ CountDownLatch latch = new CountDownLatch(1);
+ AtomicReference login = new AtomicReference<>();
+ mVolleyLogin.doLogin(mEmail, mPassword, success -> {
+ mVolleyLogin.testLoginToken(success, success1 -> {
+ login.set(success);
+ latch.countDown();
+ }, error -> latch.countDown());
+ }, error -> latch.countDown());
+ try {
+ latch.await();
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ }
+
+ log.d(login.get());
+
+ if (login.get() == null) {
+ return null;
+ } else {
+ return login.get().toJsonString();
+ }
+
+ /*for (String credential : DUMMY_CREDENTIALS) {
+ String[] pieces = credential.split(":");
+ if (pieces[0].equals(mEmail)) {
+ // Account exists, return true if the password matches.
+ return pieces[1].equals(mPassword) ? "auth token here" : null;
+ }
+ }
+
+ // TODO: register the new account here.
+ return null;*/
+ }
+
+ @Override
+ protected void onPostExecute(final String success) {
+ if (mActivity == null || mActivity.isFinishing())
+ return;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())
+ return;
+ mActivity.mAuthTask = null;
+ mActivity.showProgress(false);
+
+ if (success != null) {
+ final Intent res = new Intent();
+ res.putExtra(AccountManager.KEY_ACCOUNT_NAME, mEmail);
+ res.putExtra(AccountManager.KEY_ACCOUNT_TYPE, AccountGeneral.ACCOUNT_TYPE);
+ res.putExtra(AccountManager.KEY_AUTHTOKEN, success);
+ res.putExtra(PARAM_USER_PASS, mPassword);
+ mActivity.finishLogin(res);
+ } else {
+ mActivity.mPasswordView.setError(mActivity.getString(R.string.error_incorrect_password));
+ mActivity.mPasswordView.requestFocus();
+ }
+ }
+
+ @Override
+ protected void onCancelled() {
+ if (mActivity == null || mActivity.isFinishing())
+ return;
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1 && mActivity.isDestroyed())
+ return;
+ mActivity.mAuthTask = null;
+ mActivity.showProgress(false);
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/de/sebse/fuplanner/services/newkvv/network/Login.java b/app/src/main/java/de/sebse/fuplanner/services/newkvv/network/Login.java
new file mode 100644
index 0000000..5c67b22
--- /dev/null
+++ b/app/src/main/java/de/sebse/fuplanner/services/newkvv/network/Login.java
@@ -0,0 +1,297 @@
+package de.sebse.fuplanner.services.newkvv.network;
+
+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.types.LoginToken;
+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 Login extends HTTPService {
+ public Login(Context context) {
+ super(context);
+ }
+
+
+ public void testLoginToken(@NotNull LoginToken token, @NotNull NetworkCallback callback, @NotNull NetworkErrorCallback errorCallback) {
+ get(String.format("https://kvv.imp.fu-berlin.de/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);
+ 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) {
+ startKVVSession(success -> {
+ String kvvJSESSIONID = success.get("JSESSIONID");
+ getSAMLRequest(kvvJSESSIONID, success1 -> startIdentSession(success1.get("Location"), success11 -> {
+ String identJSESSIONID = success11.get("JSESSIONID");
+ String ident_idp_authn_lc_key = success11.get("_idp_authn_lc_key");
+ String identROUTEID = success11.get("ROUTEID");
+ loginIdent(true, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success111 -> loginIdent(false, username, password, identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, success11112 -> {
+ String ident_idp_session = success11112.get("_idp_session");
+ getSAMLResponse(identJSESSIONID, ident_idp_authn_lc_key, identROUTEID, ident_idp_session, success1111 -> loginKVV(success1111.get("RelayState"), success1111.get("SAMLResponse"), kvvJSESSIONID, success111112 -> {
+ LoginToken token = new LoginToken(username, success111112.get("shibsessionKey"), success111112.get("shibsessionName"), kvvJSESSIONID);
+ finishKVVlogin(token, success11111 -> callback.onResponse(token), error);
+ }, error), error);
+ }, error), error);
+ }, error), error);
+ }, error);
+ }
+
+ /*
+ GET https://kvv.imp.fu-berlin.de/portal/login
+ -> JSESSIONID 5c10406f-588c-4c16-96e9-c80d115417de.tomcat1
+ */
+ private void startKVVSession(final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
+ get("https://kvv.imp.fu-berlin.de/portal/login", null, response -> {
+ String cookies = response.getHeaders().get("Set-Cookie");
+ if (cookies==null) {
+ errorCallback.onError(new NetworkError(100101, -1, "Error on starting KVV session!"));
+ return;
+ }
+ HashMap object;
+ try {
+ object = getCookie(cookies, new String[]{"JSESSIONID"});
+ } catch (NoSuchFieldException e) {
+ errorCallback.onError(new NetworkError(100102, -1, "Error on starting KVV session!"));
+ return;
+ }
+ callback.onResponse(object);
+ }, error -> errorCallback.onError(new NetworkError(100100, error.networkResponse.statusCode, "Error on starting KVV session!")));
+ }
+
+ /*
+ GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
+ <- JSESSIONID
+ -> (Location-Header) https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
+ ?SAMLRequest=fZLLb.....Q8yre3X1IHwkJKE0Mnpy/V9TH4A
+ &RelayState=ss:mem:7ea01e29157b8bd906f7002176.....0d1a505f2c8bf
+ */
+ private void getSAMLRequest(String JSESSIONID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
+ HashMap cookies = new HashMap<>();
+ cookies.put("JSESSIONID", JSESSIONID);
+ get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", cookies, 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!")));
+ }
+
+ /*
+ GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
+ ?SAMLRequest=fZLLbsIwEEV/JfI+cWJAUIsgpbAoEi2IpF10UznxUKw6dupxaPn7hkdb2LD29bkzRzNGUeuGZ63fmjV8toA++K61QX58SEnrDLcCFXIjakDuK55njwvOopg3znpbWU2CDBGcV9ZMrcG2BpeD26kKnteLlGy9b5BT+rHbRapuok0bluC0MpEEmm9VWVoNfhshWnpgM7pa5gUJZt0wyogD9h+iJBiv/P6aomQTbtqSdhNtlIYzZg1SOag8zfMlCeazlLyNqpHsy1gO2V1fVsNBMuqJoUyAJaxXDUaiiyG2MDfohfEpYXEyDJM4ZKxgCe/FPI5fSbA6L36vjFTm/bal8hRC/lAUq/C02gs4PK7VBchkfHDNj8Xuwv5trPhVTiY3BeOf4DG96DmVNvypA89nK6tVtQ8yre3X1IHwkJKE0Mnpy/V9TH4A
+ &RelayState=ss:mem:7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
+ -> JSESSIONID C4B6A428BA1F50746235D03F5D107A57
+ -> _idp_authn_lc_key 57a6ae26067f374cc3d0ccfc47e27b04b47752d2a3d4eb2782af0d3994535395
+ -> ROUTEID .1
+ */
+ private void startIdentSession(String url, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
+ get(url, null, response -> {
+ String cookies = response.getHeaders().get("Set-Cookie");
+ if (cookies==null) {
+ errorCallback.onError(new NetworkError(100121, -1, "Error on starting Ident session!"));
+ return;
+ }
+ HashMap object;
+ try {
+ object = getCookie(cookies, new String[]{"JSESSIONID", "_idp_authn_lc_key", "ROUTEID"});
+ } catch (NoSuchFieldException e) {
+ errorCallback.onError(new NetworkError(100122, -1, "Error on starting Ident session!"));
+ return;
+ }
+ callback.onResponse(object);
+ }, error -> errorCallback.onError(new NetworkError(100120, error.networkResponse.statusCode, "Error on starting Ident session!")));
+ }
+
+ /*
+ POST https://identity.fu-berlin.de/idp-fub/Authn/UserPassword
+ <- j_username seedorf96
+ <- j_password neinhieristpatrick
+ <- (Header-"Content-Type") application/x-www-form-urlencoded
+ <- JSESSIONID
+ <- _idp_authn_lc_key
+ <- ROUTEID
+ -> _idp_session OTMuMTkzLjg1LjMz|LQ==|OGYxOWI4MjA2NTQ4YWUwYzJkOWM4Mjk4YzcwZDMwZmJiZjBmMTdmMzkyZGU2OWIwY2JkNmZlNjlmNTRmNzBlMQ==|wLlzQal7VqyntmG2vLNn06wt8wQ=
+ */
+ private void loginIdent(final boolean first, String username, String password, String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
+ HashMap cookies = new HashMap<>();
+ cookies.put("JSESSIONID", JSESSIONID);
+ cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
+ cookies.put("ROUTEID", ROUTEID);
+ HashMap body = new HashMap<>();
+ body.put("j_username", username);
+ body.put("j_password", password);
+ post("https://identity.fu-berlin.de/idp-fub/Authn/UserPassword", cookies, body, response -> {
+ if (first) {
+ callback.onResponse(new HashMap<>());
+ return;
+ }
+
+ String cookies1 = response.getHeaders().get("Set-Cookie");
+ if (cookies1 ==null) {
+ errorCallback.onError(new NetworkError(100131, -1, "Error on logging in to Identity Server!"));
+ return;
+ }
+ HashMap object;
+ try {
+ object = getCookie(cookies1, new String[]{"_idp_session"});
+ } catch (NoSuchFieldException e) {
+ errorCallback.onError(new NetworkError(100132, -1, "Error on logging in to Identity Server!"));
+ return;
+ }
+ callback.onResponse(object);
+ }, error -> errorCallback.onError(new NetworkError(100130, error.networkResponse.statusCode, "Error on logging in to Identity Server!")));
+ }
+
+ /*
+ GET https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO
+ <- JSESSIONID
+ <- _idp_authn_lc_key
+ <- ROUTEID
+ <- _idp_session
+ -> (BODY) RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
+ -> (BODY) SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
+ */
+ private void getSAMLResponse(String JSESSIONID, String _idp_authn_lc_key, String ROUTEID, String _idp_session, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
+ HashMap cookies = new HashMap<>();
+ cookies.put("JSESSIONID", JSESSIONID);
+ cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
+ cookies.put("ROUTEID", ROUTEID);
+ cookies.put("_idp_session", _idp_session);
+ get("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO", cookies, response -> {
+ String body = response.getParsed();
+ if (body == null) {
+ errorCallback.onError(new NetworkError(100143, -1, "Error on getting SAML response!"));
+ return;
+ }
+
+ HashMap object = new HashMap<>();
+
+ Pattern pattern = Pattern.compile("ss:mem:([0-9a-f]+)");
+ Matcher matcher = pattern.matcher(body);
+ if (!matcher.find()) {
+ errorCallback.onError(new NetworkError(100142, -1, "Error on getting SAML response!"));
+ return;
+ }
+ object.put("RelayState", "ss:mem:"+matcher.group(1));
+
+ pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)");
+ matcher = pattern.matcher(body);
+ if (!matcher.find()) {
+ errorCallback.onError(new NetworkError(100141, -1, "Error on getting SAML response!"));
+ return;
+ }
+ object.put("SAMLResponse", matcher.group(1));
+
+ callback.onResponse(object);
+ }, error -> errorCallback.onError(new NetworkError(100140, error.networkResponse.statusCode, "Error on getting SAML response!")));
+ }
+
+
+ /*
+ POST https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST
+ <- RelayState 7ea01e29157b8bd906f7002176213b6db5e1f45ebb88716a9820d1a505f2c8bf
+ <- SAMLResponse PD94bWwgdmVyc2lvbj0...........wvc2FtbDJwOlJlc3BvbnNlPg==
+ <- JSESSIONID
+ -> _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
+ _b1912c5a03d733a80bd3fee772bf68d4
+ */
+ private void loginKVV(String RelayState, String SAMLResponse, String JSESSIONID, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
+ HashMap cookies = new HashMap<>();
+ cookies.put("JSESSIONID", JSESSIONID);
+ HashMap body = new HashMap<>();
+ body.put("RelayState", RelayState);
+ body.put("SAMLResponse", SAMLResponse);
+ post("https://kvv.imp.fu-berlin.de/Shibboleth.sso/SAML2/POST", cookies, body, response -> {
+ String cookies1 = response.getHeaders().get("Set-Cookie");
+ if (cookies1 ==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(cookies1);
+ if (!matcher.find()) {
+ errorCallback.onError(new NetworkError(100152, -1, "Error on starting Ident 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 Ident session!")));
+ }
+
+
+ /*
+ GET https://kvv.imp.fu-berlin.de/sakai-login-tool/container
+ <- JSESSIONID
+ <- _shibsession_64656661756c7468747470733a2f2f6b76762e696d702e66752d6265726c696e2e64652f73686962626f6c657468
+ _b1912c5a03d733a80bd3fee772bf68d4
+ */
+ private void finishKVVlogin(LoginToken loginToken, final NetworkCallback> callback, final NetworkErrorCallback errorCallback) {
+ get("https://kvv.imp.fu-berlin.de/sakai-login-tool/container", loginToken.getCookies(), response -> callback.onResponse(new HashMap<>()), error -> errorCallback.onError(new NetworkError(100160, error.networkResponse.statusCode, "Cannot finish login process!")));
+ }
+
+
+
+
+
+
+
+
+
+
+
+
+ private String getCookie(String cookies, String name) throws NoSuchFieldException {
+ Pattern pattern = Pattern.compile(name+"=([^;]+);");
+ Matcher matcher = pattern.matcher(cookies);
+ if (!matcher.find()) {
+ log.e("GETcookie failed", name);
+ log.e("GETcookie failed", cookies);
+ throw new NoSuchFieldException();
+ }
+ return matcher.group(1);
+ }
+
+ private HashMap getCookie(String cookies, String[] names) throws NoSuchFieldException {
+ HashMap result = new HashMap<>();
+ for (String name: names) {
+ result.put(name,this.getCookie(cookies, name));
+ }
+ return result;
+ }
+}
diff --git a/app/src/main/java/de/sebse/fuplanner/tools/CustomAccountManager.java b/app/src/main/java/de/sebse/fuplanner/tools/CustomAccountManager.java
new file mode 100644
index 0000000..25d13d9
--- /dev/null
+++ b/app/src/main/java/de/sebse/fuplanner/tools/CustomAccountManager.java
@@ -0,0 +1,130 @@
+package de.sebse.fuplanner.tools;
+
+import android.accounts.Account;
+import android.accounts.AccountManager;
+import android.accounts.AuthenticatorException;
+import android.accounts.OperationCanceledException;
+import android.os.Build;
+import android.os.Bundle;
+
+import java.io.IOException;
+
+import androidx.annotation.Nullable;
+import de.sebse.fuplanner.MainActivity;
+import de.sebse.fuplanner.services.KVV.Login;
+import de.sebse.fuplanner.tools.logging.Logger;
+
+public class CustomAccountManager {
+ private final AccountManager mAccountManager;
+ private final ActivityInterface mActivityInterface;
+ private Logger log = new Logger(this);
+
+ public CustomAccountManager(AccountManager manager, ActivityInterface activityInterface) {
+ mAccountManager = manager;
+ this.mActivityInterface = activityInterface;
+ }
+
+
+
+
+
+ public void doInvalidateTokenSync(String accountType, String authTokenType) {
+ Account account = mAccountManager.getAccountsByType(accountType)[0];
+ try {
+ String token = mAccountManager.blockingGetAuthToken(account, authTokenType, true);
+ mAccountManager.invalidateAuthToken(accountType, token);
+ } catch (AuthenticatorException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (OperationCanceledException e) {
+ e.printStackTrace();
+ }
+ }
+
+ public void doInvalidateToken(String accountType, String authTokenType, Login.BooleanInterface callback) {
+ Account account = mAccountManager.getAccountsByType(accountType)[0];
+ mAccountManager.getAuthToken(account, authTokenType, null, true, accountManagerFuture -> {
+ try {
+ Bundle bnd = accountManagerFuture.getResult();
+ String token = bnd.getString(AccountManager.KEY_AUTHTOKEN);
+ mAccountManager.invalidateAuthToken(accountType, token);
+ if (callback != null)
+ callback.run(true);
+ return;
+ } catch (AuthenticatorException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (OperationCanceledException e) {
+ e.printStackTrace();
+ }
+ if (callback != null)
+ callback.run(false);
+ }, null);
+ }
+
+ public void deleteAccount(String accountType) {
+ Account[] accounts = mAccountManager.getAccountsByType(accountType);
+ int[] count = {accounts.length};
+ for (Account account: accounts) {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
+ mAccountManager.removeAccount(account, null, null, null);
+ } else {
+ mAccountManager.removeAccount(account, null, null);
+ }
+ }
+ }
+
+ public void getTokenByType(String accountType, String authTokenType, @Nullable StringInterface callback) {
+ //Account account = mAccountManager.getAccountsByType(accountType)[0];
+ mAccountManager.getAuthTokenByFeatures(accountType, authTokenType, null, mActivityInterface.get(), null, null, accountManagerFuture -> {
+ try {
+ Bundle bnd = accountManagerFuture.getResult();
+ final String authtoken = bnd.getString(AccountManager.KEY_AUTHTOKEN);
+ if (callback != null)
+ callback.run(authtoken);
+ return;
+ } catch (AuthenticatorException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (OperationCanceledException e) {
+ e.printStackTrace();
+ }
+ if (callback != null)
+ callback.run(null);
+ }, null);
+ }
+
+ public String getTokenByTypeSync(String accountType, String authTokenType) {
+ Account account = mAccountManager.getAccountsByType(accountType)[0];
+ MainActivity activity = this.mActivityInterface.get();
+ if (activity != null) {
+ try {
+ return mAccountManager.blockingGetAuthToken(account, authTokenType, true);
+ } catch (AuthenticatorException e) {
+ e.printStackTrace();
+ } catch (IOException e) {
+ e.printStackTrace();
+ } catch (OperationCanceledException e) {
+ e.printStackTrace();
+ }
+ }
+ return null;
+ }
+
+ public boolean hasAccounts(String accountType) {
+ return mAccountManager.getAccountsByType(accountType).length != 0;
+ }
+
+ @FunctionalInterface
+ public interface ActivityInterface {
+ @Nullable
+ MainActivity get();
+ }
+
+ public interface StringInterface {
+ void run(@Nullable String string);
+ }
+}
diff --git a/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java b/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java
index 3ae5cd5..f035efc 100644
--- a/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java
+++ b/app/src/main/java/de/sebse/fuplanner/tools/network/HTTPService.java
@@ -31,7 +31,7 @@ public class HTTPService {
private final EventListener errorResponseListener = new EventListener<>();
private final EventListener successResponseListener = new EventListener<>();
- protected HTTPService(Context context) {
+ public HTTPService(Context context) {
this.mContext = context;
requestQueue = Volley.newRequestQueue(context, new BetterHurlStack(false));
}
diff --git a/app/src/main/res/layout/activity_fu_authenticator.xml b/app/src/main/res/layout/activity_fu_authenticator.xml
new file mode 100644
index 0000000..6cae445
--- /dev/null
+++ b/app/src/main/res/layout/activity_fu_authenticator.xml
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/fragment_login.xml b/app/src/main/res/layout/fragment_login.xml
index ab9f3ee..93ae522 100644
--- a/app/src/main/res/layout/fragment_login.xml
+++ b/app/src/main/res/layout/fragment_login.xml
@@ -3,7 +3,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
- tools:context="de.sebse.fuplanner.fragments.LoginFragment">
+ tools:context="de.sebse.fuplanner.services.newkvv.FUAuthenticatorActivity">
Update News
Tips/Tricks
Please click BACK again to exit!
+ Sign in
+
+ Email
+ Password (optional)
+ Sign in or register
+ Sign in
+ This email address is invalid
+ This password is too short
+ This password is incorrect
+ This field is required
+ "Contacts permissions are needed for providing email
+ completions."
+
diff --git a/app/src/main/res/xml/authenticator.xml b/app/src/main/res/xml/authenticator.xml
new file mode 100644
index 0000000..1d552a4
--- /dev/null
+++ b/app/src/main/res/xml/authenticator.xml
@@ -0,0 +1,6 @@
+
+