DetectAuthenticationMethodOperation.java 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Nextcloud - Android Client
  3. *
  4. * SPDX-FileCopyrightText: 2017-2019 Tobias Kaminsky <tobias@kaminsky.me>
  5. * SPDX-FileCopyrightText: 2016-2017 Andy Scherzinger <info@andy-scherzinger.de>
  6. * SPDX-FileCopyrightText: 2015 ownCloud Inc.
  7. * SPDX-FileCopyrightText: 2014 David A. Velasco <dvelasco@solidgear.es>
  8. * SPDX-License-Identifier: GPL-2.0-only AND AGPL-3.0-or-later
  9. */
  10. package com.owncloud.android.operations;
  11. import android.content.Context;
  12. import android.net.Uri;
  13. import android.text.TextUtils;
  14. import com.owncloud.android.lib.common.OwnCloudClient;
  15. import com.owncloud.android.lib.common.operations.RemoteOperation;
  16. import com.owncloud.android.lib.common.operations.RemoteOperationResult;
  17. import com.owncloud.android.lib.common.utils.Log_OC;
  18. import com.owncloud.android.lib.resources.files.ExistenceCheckRemoteOperation;
  19. import org.apache.commons.httpclient.Header;
  20. import org.apache.commons.httpclient.HttpStatus;
  21. import java.util.ArrayList;
  22. import java.util.Locale;
  23. /**
  24. * Operation to find out what authentication method requires the server to access files.
  25. *
  26. * Basically, tries to access to the root folder without authorization and analyzes the response.
  27. *
  28. * When successful, the instance of {@link RemoteOperationResult} passed through
  29. * {@link com.owncloud.android.lib.common.operations.OnRemoteOperationListener
  30. * #onRemoteOperationFinish(RemoteOperation, RemoteOperationResult)} returns in
  31. * {@link RemoteOperationResult#getData()} a value of {@link AuthenticationMethod}.
  32. */
  33. public class DetectAuthenticationMethodOperation extends RemoteOperation {
  34. private static final String TAG = DetectAuthenticationMethodOperation.class.getSimpleName();
  35. public enum AuthenticationMethod {
  36. UNKNOWN,
  37. NONE,
  38. BASIC_HTTP_AUTH,
  39. SAML_WEB_SSO,
  40. BEARER_TOKEN
  41. }
  42. private Context mContext;
  43. /**
  44. * Constructor
  45. *
  46. * @param context Android context of the caller.
  47. */
  48. public DetectAuthenticationMethodOperation(Context context) {
  49. mContext = context;
  50. }
  51. /**
  52. * Performs the operation.
  53. *
  54. * Triggers a check of existence on the root folder of the server, granting
  55. * that the request is not authenticated.
  56. *
  57. * Analyzes the result of check to find out what authentication method, if
  58. * any, is requested by the server.
  59. */
  60. @Override
  61. protected RemoteOperationResult run(OwnCloudClient client) {
  62. RemoteOperationResult result = null;
  63. AuthenticationMethod authMethod = AuthenticationMethod.UNKNOWN;
  64. RemoteOperation operation = new ExistenceCheckRemoteOperation("", mContext, false);
  65. client.clearCredentials();
  66. client.setFollowRedirects(false);
  67. // try to access the root folder, following redirections but not SAML SSO redirections
  68. result = operation.execute(client);
  69. String redirectedLocation = result.getRedirectedLocation();
  70. while (!TextUtils.isEmpty(redirectedLocation) && !result.isIdPRedirection()) {
  71. client.setBaseUri(Uri.parse(result.getRedirectedLocation()));
  72. result = operation.execute(client);
  73. redirectedLocation = result.getRedirectedLocation();
  74. }
  75. // analyze response
  76. if (result.getHttpCode() == HttpStatus.SC_UNAUTHORIZED || result.getHttpCode() == HttpStatus.SC_FORBIDDEN) {
  77. ArrayList<String> authHeaders = result.getAuthenticateHeaders();
  78. for (String header : authHeaders) {
  79. // currently we only support basic auth
  80. if (header.toLowerCase(Locale.ROOT).contains("basic")) {
  81. authMethod = AuthenticationMethod.BASIC_HTTP_AUTH;
  82. break;
  83. }
  84. }
  85. // else - fall back to UNKNOWN
  86. } else if (result.isSuccess()) {
  87. authMethod = AuthenticationMethod.NONE;
  88. } else if (result.isIdPRedirection()) {
  89. authMethod = AuthenticationMethod.SAML_WEB_SSO;
  90. }
  91. // else - fall back to UNKNOWN
  92. Log_OC.d(TAG, "Authentication method found: " + authenticationMethodToString(authMethod));
  93. if (authMethod != AuthenticationMethod.UNKNOWN) {
  94. result = new RemoteOperationResult(true, result.getHttpCode(), result.getHttpPhrase(), new Header[0]);
  95. }
  96. ArrayList<Object> data = new ArrayList<>();
  97. data.add(authMethod);
  98. result.setData(data);
  99. return result; // same result instance, so that other errors
  100. // can be handled by the caller transparently
  101. }
  102. private String authenticationMethodToString(AuthenticationMethod value) {
  103. switch (value) {
  104. case NONE:
  105. return "NONE";
  106. case BASIC_HTTP_AUTH:
  107. return "BASIC_HTTP_AUTH";
  108. case BEARER_TOKEN:
  109. return "BEARER_TOKEN";
  110. case SAML_WEB_SSO:
  111. return "SAML_WEB_SSO";
  112. default:
  113. return "UNKNOWN";
  114. }
  115. }
  116. }