Login Finished

This commit is contained in:
Caesar2011
2018-12-18 23:54:21 +01:00
parent cde5fc3582
commit fd18e4b61a
7 changed files with 286 additions and 420 deletions

View File

@@ -1,12 +1,7 @@
package de.sebse.fuplanner;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
import android.accounts.AuthenticatorException;
import android.accounts.OperationCanceledException;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.view.Menu;
import android.view.MenuItem;
@@ -19,7 +14,6 @@ import com.google.android.material.navigation.NavigationView;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
@@ -35,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;
@@ -54,6 +47,7 @@ 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;
@@ -75,6 +69,7 @@ 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;
@Deprecated
private static final int FRAGMENT_LOGIN = 3;
private static final int FRAGMENT_SCHEDULE = 4;
private static final int FRAGMENT_CANTEENS = 5;
@@ -101,12 +96,14 @@ public class MainActivity extends AppCompatActivity
private boolean mOfflineBanner;
private final NewAsyncQueue mQueue = new NewAsyncQueue();
private long mDoubleBackToExitPressedOnce = 0;
private AccountManager mAccountManager;
private CustomAccountManager mAccountManager;
private boolean isPaused = false;
private boolean isLoggedInBeforePause = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mAccountManager = AccountManager.get(this);
mAccountManager = new CustomAccountManager(AccountManager.get(this), () -> MainActivity.this);
int desiredPage = getDefaultFragmentAfterLogin();
String desiredData = "";
if (savedInstanceState != null) {
@@ -128,12 +125,52 @@ 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.getTokenForAccountCreateIfNeeded(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV);
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());
});
}
}
@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().reset();
getKVV().account().restoreOnlineLogin(isRestored -> {
log.d("onResume", isRestored);
updateNavigation();
if (isRestored && !isLoggedInBeforePause)
changeFragment(getDefaultFragmentAfterLogin());
else if (!isRestored && isLoggedInBeforePause)
changeFragment(getDefaultFragmentAfterLogin());
});
}
isPaused = false;
}
@Override
@@ -163,12 +200,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);
//getTokenForAccountCreateIfNeeded(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV);
}
}
}
@@ -266,7 +301,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) {
@@ -323,11 +358,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.getTokenForAccountCreateIfNeeded(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV);
}
private void toLoginState(String fullName, String email, int newFragment, boolean onlineMode) {
@@ -362,9 +402,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;
@@ -486,7 +526,7 @@ public class MainActivity extends AppCompatActivity
if (drawer.isDrawerOpen(GravityCompat.START)) {
drawer.closeDrawer(GravityCompat.START);
}
changeFragment(FRAGMENT_LOGIN);
mAccountManager.getTokenForAccountCreateIfNeeded(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV);
});
}
@@ -537,7 +577,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();
@@ -563,53 +603,8 @@ public class MainActivity extends AppCompatActivity
});
}
private void doInvalidateToken(String accountType, String authTokenType) {
//String token = mAccountManager.blockingGetAuthToken();
Account account = mAccountManager.getAccountsByType(accountType)[0];
String token = null;
try {
token = mAccountManager.blockingGetAuthToken(account, authTokenType, true);
log.d("hihihi", accountType, authTokenType, token);
mAccountManager.invalidateAuthToken(accountType, token);
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (OperationCanceledException e) {
e.printStackTrace();
}
}
private 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);
}
}
}
private void getTokenForAccountCreateIfNeeded(String accountType, String authTokenType) {
deleteAccount(accountType);
final AccountManagerFuture<Bundle> future = mAccountManager.getAuthTokenByFeatures(accountType, authTokenType, null, this, null, null,
future1 -> {
Bundle bnd = null;
try {
bnd = future1.getResult();
final String authtoken = bnd.getString(AccountManager.KEY_AUTHTOKEN);
showToast(((authtoken != null) ? "SUCCESS!\ntoken: " + authtoken : "FAIL"));
log.d("udinic", "GetTokenForAccount Bundle is " + bnd);
} catch (Exception e) {
e.printStackTrace();
showToast(e.getMessage());
}
}
, null);
}
@@ -705,4 +700,9 @@ public class MainActivity extends AppCompatActivity
public void onKVVNetworkResponse(NetworkResponse error) {
setRefreshFailedBanner(error != null);
}
@Override
public CustomAccountManager getAccountManager() {
return mAccountManager;
}
}

View File

@@ -6,7 +6,6 @@ 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;
@@ -47,12 +46,12 @@ public class LoginFragment extends Fragment {
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());
}
//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 -> {

View File

@@ -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();
}

View File

@@ -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,41 @@ public class Login extends HTTPService {
this.mListener = listener;
}
public void reset() {
mToken = null;
mLoginPending = false;
mOnlineMode = false;
}
public void doOnlineLogin(@NotNull String username, @NotNull String password, NetworkCallback<LoginToken> callback, NetworkErrorCallback errorCallback) {
if (mLoginPending) {
errorCallback.onError(new NetworkError(100160, -1, "Login already pending!"));
log.t();
}
//public boolean restoreOnlineLogin() {
// return restoreLogin(true);
//}
//public boolean doOfflineLogin() {
// return restoreLogin(false);
//}
public void restoreOnlineLogin(BooleanInterface callback) {
if (mLoginPending || mToken != null) {
callback.run(false);
return;
}
mLoginPending = true;
doLogin(username, password, token -> {
testLoginToken(token, token2 -> {
setToken(token2, true);
LoginToken.load(mListener.getAccountManager(), token -> {
boolean result = setToken(token, true);
mLoginPending = false;
callback.onResponse(token2);
}, error -> {
mLoginPending = false;
errorCallback.onError(error);
});
}, error -> {
mLoginPending = false;
errorCallback.onError(error);
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 +71,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 +128,25 @@ public class Login extends HTTPService {
mRefreshCallbacks.add(success, error);
if (!isFirst)
return;
mListener.getCredentials(credentials -> {
CustomAccountManager manager = mListener.getAccountManager();
manager.invalidate(AccountGeneral.ACCOUNT_TYPE, AccountGeneral.AUTHTOKEN_TYPE_KVV);
reset();
restoreOnlineLogin(isRestored -> {
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 +166,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<LoginToken> 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<HashMap<String, String>> 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<String, String> 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<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
HashMap<String, String> 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<String, String> 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<HashMap<String, String>> 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<String, String> 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<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
HashMap<String, String> cookies = new HashMap<>();
cookies.put("JSESSIONID", JSESSIONID);
cookies.put("_idp_authn_lc_key", _idp_authn_lc_key);
cookies.put("ROUTEID", ROUTEID);
HashMap<String, String> 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<String, String> 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<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
HashMap<String, String> 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<String, String> object = new HashMap<>();
Pattern pattern = Pattern.compile("ss&#x3a;mem&#x3a;([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<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
HashMap<String, String> cookies = new HashMap<>();
cookies.put("JSESSIONID", JSESSIONID);
HashMap<String, String> 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<String, String> 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<HashMap<String, String>> 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<String, String> getCookie(String cookies, String[] names) throws NoSuchFieldException {
HashMap<String, String> result = new HashMap<>();
for (String name: names) {
result.put(name,this.getCookie(cookies, name));
}
return result;
public interface BooleanInterface {
void run(boolean bool);
}
}

View File

@@ -163,6 +163,8 @@ public class ModulesList extends HTTPService {
try {
JSONObject site = sites.getJSONObject(i);
String semester_string = site.getJSONObject("props").optString("term_eid", null);
if (semester_string == null)
continue;
Semester semester = new Semester(semester_string);
HashSet<String> lvNumbers = new HashSet<>();
String kvv_lvnumbers = site.getJSONObject("props").optString("kvv_lvnumbers", null);

View File

@@ -5,23 +5,22 @@ import android.content.Context;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
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;
@@ -39,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) {
@@ -156,4 +157,8 @@ public class LoginToken implements Serializable {
return null;
}
}
public interface LoginTokenInterface {
void run(LoginToken token);
}
}

View File

@@ -0,0 +1,134 @@
package de.sebse.fuplanner.tools;
import android.accounts.Account;
import android.accounts.AccountManager;
import android.accounts.AccountManagerFuture;
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.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;
}
private void doInvalidateToken(String accountType, String authTokenType) {
//String token = mAccountManager.blockingGetAuthToken();
Account account = mAccountManager.getAccountsByType(accountType)[0];
String token = null;
try {
token = mAccountManager.blockingGetAuthToken(account, authTokenType, true);
//log.d("hihihi", accountType, authTokenType, token);
mAccountManager.invalidateAuthToken(accountType, token);
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (OperationCanceledException e) {
e.printStackTrace();
}
}
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 getTokenForAccountCreateIfNeeded(String accountType, String authTokenType) {
MainActivity activity = this.mActivityInterface.get();
if (activity != null) {
final AccountManagerFuture<Bundle> future = mAccountManager.getAuthTokenByFeatures(accountType, authTokenType, null, activity, null, null,
future1 -> {
Bundle bnd = null;
try {
bnd = future1.getResult();
final String authtoken = bnd.getString(AccountManager.KEY_AUTHTOKEN);
//showToast(((authtoken != null) ? "SUCCESS!\ntoken: " + authtoken : "FAIL"));
//log.d("udinic", "GetTokenForAccount Bundle is " + bnd);
} catch (Exception e) {
e.printStackTrace();
//showToast(e.getMessage());
}
}
, null);
}
}
public void getTokenByType(String accountType, String authTokenType, StringInterface callback) {
Account account = mAccountManager.getAccountsByType(accountType)[0];
mAccountManager.getAuthToken(account, authTokenType, null, true, accountManagerFuture -> {
try {
Bundle bnd = accountManagerFuture.getResult();
final String authtoken = bnd.getString(AccountManager.KEY_AUTHTOKEN);
callback.run(authtoken);
return;
} catch (AuthenticatorException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (OperationCanceledException e) {
e.printStackTrace();
}
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);
}
public void invalidate(String accountType, String authTokenType) {
mAccountManager.invalidateAuthToken(accountType, authTokenType);
}
}