Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/workflows/build-tester-apk.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ jobs:
COMMIT_HASH=$(git rev-parse HEAD)
echo "Commit hash: $COMMIT_HASH"
echo "commit_hash=$COMMIT_HASH" >> $GITHUB_OUTPUT
echo "commit_hash=$COMMIT_HASH" >> "$GITHUB_ENV"

- name: Setup JDK
uses: actions/setup-java@v5
Expand Down Expand Up @@ -99,6 +100,9 @@ jobs:
uses: softprops/action-gh-release@v2
with:
tag_name: build-tester-apk-${{ github.run_number }}
target_commitish: ${{ env.commit_hash }}
name: build-tester-apk build ${{ github.run_number }}
files: ${{ steps.set_artifact.outputs.artifact_name }}
prerelease: true
generate_release_notes: false
body: Built from ${{ env.commit_hash }}
2 changes: 1 addition & 1 deletion opencloudApp/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ android {

testInstrumentationRunner "eu.opencloud.android.utils.OCTestAndroidJUnitRunner"

versionCode = 4
versionCode = 5
versionName = "1.2.0"

buildConfigField "String", gitRemote, "\"" + getGitOriginRemote() + "\""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_CLIENT_REGISTRATION_CLIENT_SECRET;
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_OAUTH2_REFRESH_TOKEN;
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_OAUTH2_SCOPE;
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_OIDC_ISSUER;
import static eu.opencloud.android.presentation.authentication.AuthenticatorConstants.KEY_AUTH_TOKEN_TYPE;
import static org.koin.java.KoinJavaComponent.inject;

Expand Down Expand Up @@ -333,9 +334,13 @@ private String refreshToken(

String baseUrl = accountManager.getUserData(account, AccountUtils.Constants.KEY_OC_BASE_URL);

// OIDC Discovery
// OIDC Discovery: prefer the stored webfinger issuer (points to the real IDP),
// fall back to baseUrl for accounts created before webfinger support.
String oidcIssuer = accountManager.getUserData(account, KEY_OIDC_ISSUER);
String discoveryUrl = (oidcIssuer != null) ? oidcIssuer : baseUrl;

@NotNull Lazy<OIDCDiscoveryUseCase> oidcDiscoveryUseCase = inject(OIDCDiscoveryUseCase.class);
OIDCDiscoveryUseCase.Params oidcDiscoveryUseCaseParams = new OIDCDiscoveryUseCase.Params(baseUrl);
OIDCDiscoveryUseCase.Params oidcDiscoveryUseCaseParams = new OIDCDiscoveryUseCase.Params(discoveryUrl);
UseCaseResult<OIDCServerConfiguration> oidcServerConfigurationUseCaseResult =
oidcDiscoveryUseCase.getValue().invoke(oidcDiscoveryUseCaseParams);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ import androidx.core.widget.doAfterTextChanged
import eu.opencloud.android.BuildConfig
import eu.opencloud.android.MainApp.Companion.accountType
import eu.opencloud.android.R
import eu.opencloud.android.data.authentication.KEY_OIDC_ISSUER
import eu.opencloud.android.data.authentication.KEY_PREFERRED_USERNAME
import eu.opencloud.android.data.authentication.KEY_USER_ID
import eu.opencloud.android.databinding.AccountSetupBinding
Expand All @@ -59,7 +60,6 @@ import eu.opencloud.android.domain.exceptions.OpencloudVersionNotSupportedExcept
import eu.opencloud.android.domain.exceptions.SSLErrorCode
import eu.opencloud.android.domain.exceptions.SSLErrorException
import eu.opencloud.android.domain.exceptions.ServerNotReachableException
import eu.opencloud.android.domain.exceptions.StateMismatchException
import eu.opencloud.android.domain.exceptions.UnauthorizedException
import eu.opencloud.android.domain.server.model.ServerInfo
import eu.opencloud.android.extensions.checkPasscodeEnforced
Expand Down Expand Up @@ -312,7 +312,13 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
authenticationViewModel.accountDiscovery.observe(this) {
if (it.peekContent() is UIResult.Success) {
notifyDocumentsProviderRoots(applicationContext)
launchFileDisplayActivity()
if (authenticationViewModel.launchedFromDeepLink ||
(isTaskRoot && accountAuthenticatorResponse == null)
) {
launchFileDisplayActivity()
} else {
finish()
}
} else {
binding.authStatusText.run {
text = context.getString(R.string.login_account_preparing)
Expand Down Expand Up @@ -559,10 +565,17 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
resultBundle = intent.extras
setResult(Activity.RESULT_OK, intent)

val account = Account(accountName, contextProvider.getString(R.string.account_type))
val am = AccountManager.get(this)

// Store preferred_username from id_token for login_hint on re-login
preferredUsername?.let { prefUsername ->
val account = Account(accountName, contextProvider.getString(R.string.account_type))
AccountManager.get(this).setUserData(account, KEY_PREFERRED_USERNAME, prefUsername)
preferredUsername?.let { am.setUserData(account, KEY_PREFERRED_USERNAME, it) }

// Store OIDC issuer from webfinger so AccountAuthenticator can do OIDC discovery
// against the correct IDP (not the cloud server which may proxy stale config)
val serverInfo = authenticationViewModel.serverInfo.value?.peekContent()?.getStoredData()
if (serverInfo is ServerInfo.OIDCServer) {
am.setUserData(account, KEY_OIDC_ISSUER, serverInfo.oidcServerConfiguration.issuer)
}

authenticationViewModel.discoverAccount(accountName = accountName, discoveryNeeded = loginAction == ACTION_CREATE)
Expand Down Expand Up @@ -686,6 +699,10 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
super.onNewIntent(intent)
intent?.let {
Timber.d("onNewIntent received with data: ${it.data}")
if (!::binding.isInitialized) {
Timber.w("onNewIntent received before binding initialized, ignoring OAuth response")
return
}
setIntent(it)
handleGetAuthorizationCodeResponse(it)
}
Expand All @@ -696,8 +713,9 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
val state = intent.data?.getQueryParameter("state")

if (state != authenticationViewModel.oidcState) {
Timber.e("OAuth request to get authorization code failed. State mismatching, maybe somebody is trying a CSRF attack.")
updateOAuthStatusIconAndText(StateMismatchException())
Timber.e("OAuth: state mismatch (expected=${authenticationViewModel.oidcState}, got=$state). Finishing.")
showMessageInSnackbar(message = getString(R.string.auth_oauth_error))
finish()
} else {
if (authorizationCode != null) {
Timber.d("Authorization code received [$authorizationCode]. Let's exchange it for access token")
Expand Down Expand Up @@ -996,6 +1014,10 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
}

private fun updateOAuthStatusIconAndText(authorizationException: Throwable?) {
if (!::binding.isInitialized) {
Timber.w("updateOAuthStatusIconAndText called before binding initialized, ignoring")
return
}
binding.serverStatusText.run {
setCompoundDrawablesWithIntrinsicBounds(R.drawable.common_error, 0, 0, 0)
text =
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -188,8 +188,16 @@ object ThumbnailsRequester : KoinComponent {

override fun intercept(chain: Interceptor.Chain): Response {
val openCloudClient = clientManager.getClientForCoilThumbnails(accountName)
val credentials = openCloudClient.credentials
?: return Response.Builder()
.request(chain.request())
.protocol(okhttp3.Protocol.HTTP_1_1)
.code(401)
.message("No credentials available")
.body(okhttp3.ResponseBody.create(null, ""))
.build()
val requestHeaders = hashMapOf(
AUTHORIZATION_HEADER to openCloudClient.credentials.headerAuth,
AUTHORIZATION_HEADER to credentials.headerAuth,
ACCEPT_ENCODING_HEADER to ACCEPT_ENCODING_IDENTITY,
USER_AGENT_HEADER to SingleSessionManager.getUserAgent(),
OC_X_REQUEST_ID to RandomUtils.generateRandomUUID(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@ const val KEY_FEATURE_SPACES = "KEY_FEATURE_SPACES"
*/
const val KEY_PREFERRED_USERNAME = "oc_preferred_username"

/**
* OIDC issuer URL from webfinger, used for token refresh OIDC discovery
*/
const val KEY_OIDC_ISSUER = "oc_oidc_issuer"

const val KEY_CLIENT_REGISTRATION_CLIENT_ID = "client_id"
const val KEY_CLIENT_REGISTRATION_CLIENT_SECRET = "client_secret"
const val KEY_CLIENT_REGISTRATION_CLIENT_EXPIRATION_DATE = "client_secret_expires_at"
Expand Down
Loading