Fix GetServerInfo and GetStatus operations

Signed-off-by: ZetaTom <70907959+ZetaTom@users.noreply.github.com>
This commit is contained in:
ZetaTom 2024-01-10 09:49:18 +01:00
parent 4c550c72c6
commit ce101d2c9b
No known key found for this signature in database
GPG Key ID: 3536EB6B4203D957
3 changed files with 74 additions and 102 deletions

View File

@ -898,7 +898,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
*
* @param result Result of the check.
*/
private void onGetServerInfoFinish(RemoteOperationResult result) {
private void onGetServerInfoFinish(RemoteOperationResult<GetServerInfoOperation.ServerInfo> result) {
/// update activity state
mWaitingForOpId = Long.MAX_VALUE;
@ -908,7 +908,7 @@ public class AuthenticatorActivity extends AccountAuthenticatorActivity
// 2. server is installed
// 3. we got the server version
// 4. we got the authentication method required by the server
mServerInfo = (GetServerInfoOperation.ServerInfo) (result.getData().get(0));
mServerInfo = result.getResultData();
// show outdated warning
if (CapabilityUtils.checkOutdatedWarning(getResources(),

View File

@ -20,11 +20,10 @@
package com.owncloud.android.operations;
import android.content.Context;
import android.net.Uri;
import android.text.TextUtils;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.nextcloud.common.NextcloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.utils.Log_OC;
@ -38,68 +37,43 @@ import java.util.Locale;
/**
* Operation to find out what authentication method requires the server to access files.
*
* <p>
* Basically, tries to access to the root folder without authorization and analyzes the response.
*
* <p>
* When successful, the instance of {@link RemoteOperationResult} passed through
* {@link com.owncloud.android.lib.common.operations.OnRemoteOperationListener
* #onRemoteOperationFinish(RemoteOperation, RemoteOperationResult)} returns in
* {@link RemoteOperationResult#getData()} a value of {@link AuthenticationMethod}.
* {@link com.owncloud.android.lib.common.operations.OnRemoteOperationListener #onRemoteOperationFinish(RemoteOperation,
* RemoteOperationResult)} returns in {@link RemoteOperationResult#getData()} a value of {@link AuthenticationMethod}.
*/
public class DetectAuthenticationMethodOperation extends RemoteOperation {
public class DetectAuthenticationMethodOperation extends RemoteOperation<DetectAuthenticationMethodOperation.AuthenticationMethod> {
private static final String TAG = DetectAuthenticationMethodOperation.class.getSimpleName();
public enum AuthenticationMethod {
UNKNOWN,
NONE,
BASIC_HTTP_AUTH,
SAML_WEB_SSO,
BEARER_TOKEN
}
private Context mContext;
/**
* Constructor
*
* @param context Android context of the caller.
*/
public DetectAuthenticationMethodOperation(Context context) {
mContext = context;
}
/**
* Performs the operation.
*
* Triggers a check of existence on the root folder of the server, granting
* that the request is not authenticated.
*
* Analyzes the result of check to find out what authentication method, if
* any, is requested by the server.
* Performs the operation.
* <p>
* Triggers a check of existence on the root folder of the server, granting that the request is not authenticated.
* <p>
* Analyzes the result of check to find out what authentication method, if any, is requested by the server.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
RemoteOperationResult result = null;
AuthenticationMethod authMethod = AuthenticationMethod.UNKNOWN;
RemoteOperation operation = new ExistenceCheckRemoteOperation("", mContext, false);
client.clearCredentials();
public RemoteOperationResult<AuthenticationMethod> run(NextcloudClient client) {
RemoteOperation<Void> operation = new ExistenceCheckRemoteOperation("", false);
client.setCredentials("");
client.setFollowRedirects(false);
// try to access the root folder, following redirections but not SAML SSO redirections
result = operation.execute(client);
String redirectedLocation = result.getRedirectedLocation();
while (!TextUtils.isEmpty(redirectedLocation) && !result.isIdPRedirection()) {
client.setBaseUri(Uri.parse(result.getRedirectedLocation()));
result = operation.execute(client);
redirectedLocation = result.getRedirectedLocation();
RemoteOperationResult<Void> existanceCheckResult = operation.execute(client);
String redirectedLocation = existanceCheckResult.getRedirectedLocation();
while (!TextUtils.isEmpty(redirectedLocation) && !existanceCheckResult.isIdPRedirection()) {
client.setBaseUri(Uri.parse(existanceCheckResult.getRedirectedLocation()));
existanceCheckResult = operation.execute(client);
redirectedLocation = existanceCheckResult.getRedirectedLocation();
}
// analyze response
if (result.getHttpCode() == HttpStatus.SC_UNAUTHORIZED || result.getHttpCode() == HttpStatus.SC_FORBIDDEN) {
ArrayList<String> authHeaders = result.getAuthenticateHeaders();
AuthenticationMethod authMethod = AuthenticationMethod.UNKNOWN;
if (existanceCheckResult.getHttpCode() == HttpStatus.SC_UNAUTHORIZED || existanceCheckResult.getHttpCode() == HttpStatus.SC_FORBIDDEN) {
ArrayList<String> authHeaders = existanceCheckResult.getAuthenticateHeaders();
for (String header : authHeaders) {
// currently we only support basic auth
@ -110,38 +84,35 @@ public class DetectAuthenticationMethodOperation extends RemoteOperation {
}
// else - fall back to UNKNOWN
} else if (result.isSuccess()) {
} else if (existanceCheckResult.isSuccess()) {
authMethod = AuthenticationMethod.NONE;
} else if (result.isIdPRedirection()) {
} else if (existanceCheckResult.isIdPRedirection()) {
authMethod = AuthenticationMethod.SAML_WEB_SSO;
}
// else - fall back to UNKNOWN
Log_OC.d(TAG, "Authentication method found: " + authenticationMethodToString(authMethod));
if (authMethod != AuthenticationMethod.UNKNOWN) {
result = new RemoteOperationResult(true, result.getHttpCode(), result.getHttpPhrase(), new Header[0]);
}
ArrayList<Object> data = new ArrayList<>();
data.add(authMethod);
result.setData(data);
boolean isSuccess = authMethod != AuthenticationMethod.UNKNOWN || existanceCheckResult.isSuccess();
RemoteOperationResult<AuthenticationMethod> result = new RemoteOperationResult<>(isSuccess,
existanceCheckResult.getHttpCode(), existanceCheckResult.getHttpPhrase(), new Header[0]);
result.setResultData(authMethod);
return result; // same result instance, so that other errors
// can be handled by the caller transparently
}
private String authenticationMethodToString(AuthenticationMethod value) {
switch (value) {
case NONE:
return "NONE";
case BASIC_HTTP_AUTH:
return "BASIC_HTTP_AUTH";
case BEARER_TOKEN:
return "BEARER_TOKEN";
case SAML_WEB_SSO:
return "SAML_WEB_SSO";
default:
return "UNKNOWN";
}
return switch (value) {
case NONE -> "NONE";
case BASIC_HTTP_AUTH -> "BASIC_HTTP_AUTH";
case BEARER_TOKEN -> "BEARER_TOKEN";
case SAML_WEB_SSO -> "SAML_WEB_SSO";
default -> "UNKNOWN";
};
}
public enum AuthenticationMethod {
UNKNOWN, NONE, BASIC_HTTP_AUTH, SAML_WEB_SSO, BEARER_TOKEN
}
}

View File

@ -23,8 +23,8 @@ package com.owncloud.android.operations;
import android.content.Context;
import com.nextcloud.common.NextcloudClient;
import com.owncloud.android.authentication.AuthenticatorUrlUtils;
import com.owncloud.android.lib.common.OwnCloudClient;
import com.owncloud.android.lib.common.operations.RemoteOperation;
import com.owncloud.android.lib.common.operations.RemoteOperationResult;
import com.owncloud.android.lib.common.operations.RemoteOperationResult.ResultCode;
@ -33,23 +33,26 @@ import com.owncloud.android.lib.resources.status.GetStatusRemoteOperation;
import com.owncloud.android.lib.resources.status.OwnCloudVersion;
import com.owncloud.android.operations.DetectAuthenticationMethodOperation.AuthenticationMethod;
import java.util.ArrayList;
import org.apache.commons.httpclient.Header;
import java.util.Locale;
import kotlin.Pair;
/**
* Get basic information from an ownCloud server given its URL.
*
* Checks the existence of a configured ownCloud server in the URL, gets its version
* and finds out what authentication method is needed to access files in it.
* <p>
* Checks the existence of a configured ownCloud server in the URL, gets its version and finds out what authentication
* method is needed to access files in it.
*/
public class GetServerInfoOperation extends RemoteOperation {
public class GetServerInfoOperation extends RemoteOperation<GetServerInfoOperation.ServerInfo> {
private static final String TAG = GetServerInfoOperation.class.getSimpleName();
private String mUrl;
private Context mContext;
private ServerInfo mResultData;
private final String mUrl;
private final Context mContext;
private final ServerInfo mResultData;
/**
* Constructor.
@ -67,44 +70,42 @@ public class GetServerInfoOperation extends RemoteOperation {
/**
* Performs the operation
*
* @return Result of the operation. If successful, includes an instance of
* {@link ServerInfo} with the information retrieved from the server.
* Call {@link RemoteOperationResult#getData()}.get(0) to get it.
* @return Result of the operation. If successful, includes an instance of {@link ServerInfo} with the information
* retrieved from the server. Call {@link RemoteOperationResult#getResultData()} to get it.
*/
@Override
protected RemoteOperationResult run(OwnCloudClient client) {
@Override
public RemoteOperationResult<ServerInfo> run(NextcloudClient client) {
// first: check the status of the server (including its version)
// first: check the status of the server (including its version)
GetStatusRemoteOperation getStatus = new GetStatusRemoteOperation(mContext);
RemoteOperationResult result = getStatus.execute(client);
RemoteOperationResult<Pair<OwnCloudVersion, Boolean>> getStatusResult = getStatus.execute(client);
RemoteOperationResult<ServerInfo> result = new RemoteOperationResult<>(getStatusResult.isSuccess(),
getStatusResult.getHttpCode(),
getStatusResult.getHttpPhrase(),
new Header[0]);
if (result.isSuccess()) {
if (getStatusResult.isSuccess()) {
// second: get authentication method required by the server
mResultData.mVersion = (OwnCloudVersion) result.getData().get(0);
mResultData.hasExtendedSupport = (boolean) result.getData().get(1);
mResultData.mIsSslConn = result.getCode() == ResultCode.OK_SSL;
mResultData.mVersion = getStatusResult.getResultData().component1();
mResultData.hasExtendedSupport = getStatusResult.getResultData().component2();
mResultData.mIsSslConn = getStatusResult.getCode() == ResultCode.OK_SSL;
mResultData.mBaseUrl = normalizeProtocolPrefix(mUrl, mResultData.mIsSslConn);
RemoteOperationResult detectAuthResult = detectAuthorizationMethod(client);
RemoteOperationResult<AuthenticationMethod> detectAuthResult = detectAuthorizationMethod(client);
// third: merge results
if (detectAuthResult.isSuccess()) {
mResultData.mAuthMethod = (AuthenticationMethod) detectAuthResult.getData().get(0);
ArrayList<Object> data = new ArrayList<Object>();
data.add(mResultData);
result.setData(data);
} else {
result = detectAuthResult;
}
mResultData.mAuthMethod = detectAuthResult.getResultData();
result.setResultData(mResultData);
}
return result;
}
private RemoteOperationResult detectAuthorizationMethod(OwnCloudClient client) {
private RemoteOperationResult<AuthenticationMethod> detectAuthorizationMethod(NextcloudClient client) {
Log_OC.d(TAG, "Trying empty authorization to detect authentication method");
DetectAuthenticationMethodOperation operation =
new DetectAuthenticationMethodOperation(mContext);
new DetectAuthenticationMethodOperation();
return operation.execute(client);
}