Skip to content

Commit 59cfa6e

Browse files
authored
Merge pull request #113 from opencloud-eu/release_1.2
Release 1.2.0 (second release branch, first one got already merged)
2 parents 901f157 + 7c73c99 commit 59cfa6e

6 files changed

Lines changed: 55 additions & 11 deletions

File tree

.github/workflows/build-tester-apk.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ jobs:
4545
COMMIT_HASH=$(git rev-parse HEAD)
4646
echo "Commit hash: $COMMIT_HASH"
4747
echo "commit_hash=$COMMIT_HASH" >> $GITHUB_OUTPUT
48+
echo "commit_hash=$COMMIT_HASH" >> "$GITHUB_ENV"
4849
4950
- name: Setup JDK
5051
uses: actions/setup-java@v5
@@ -99,6 +100,9 @@ jobs:
99100
uses: softprops/action-gh-release@v2
100101
with:
101102
tag_name: build-tester-apk-${{ github.run_number }}
103+
target_commitish: ${{ env.commit_hash }}
102104
name: build-tester-apk build ${{ github.run_number }}
103105
files: ${{ steps.set_artifact.outputs.artifact_name }}
104106
prerelease: true
107+
generate_release_notes: false
108+
body: Built from ${{ env.commit_hash }}

opencloudApp/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ android {
100100

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

103-
versionCode = 4
103+
versionCode = 5
104104
versionName = "1.2.0"
105105

106106
buildConfigField "String", gitRemote, "\"" + getGitOriginRemote() + "\""

opencloudApp/src/main/java/eu/opencloud/android/presentation/authentication/AccountAuthenticator.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@
5555
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_CLIENT_REGISTRATION_CLIENT_SECRET;
5656
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_OAUTH2_REFRESH_TOKEN;
5757
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_OAUTH2_SCOPE;
58+
import static eu.opencloud.android.data.authentication.AuthenticationConstantsKt.KEY_OIDC_ISSUER;
5859
import static eu.opencloud.android.presentation.authentication.AuthenticatorConstants.KEY_AUTH_TOKEN_TYPE;
5960
import static org.koin.java.KoinJavaComponent.inject;
6061

@@ -333,9 +334,13 @@ private String refreshToken(
333334

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

336-
// OIDC Discovery
337+
// OIDC Discovery: prefer the stored webfinger issuer (points to the real IDP),
338+
// fall back to baseUrl for accounts created before webfinger support.
339+
String oidcIssuer = accountManager.getUserData(account, KEY_OIDC_ISSUER);
340+
String discoveryUrl = (oidcIssuer != null) ? oidcIssuer : baseUrl;
341+
337342
@NotNull Lazy<OIDCDiscoveryUseCase> oidcDiscoveryUseCase = inject(OIDCDiscoveryUseCase.class);
338-
OIDCDiscoveryUseCase.Params oidcDiscoveryUseCaseParams = new OIDCDiscoveryUseCase.Params(baseUrl);
343+
OIDCDiscoveryUseCase.Params oidcDiscoveryUseCaseParams = new OIDCDiscoveryUseCase.Params(discoveryUrl);
339344
UseCaseResult<OIDCServerConfiguration> oidcServerConfigurationUseCaseResult =
340345
oidcDiscoveryUseCase.getValue().invoke(oidcDiscoveryUseCaseParams);
341346

opencloudApp/src/main/java/eu/opencloud/android/presentation/authentication/LoginActivity.kt

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ import androidx.core.widget.doAfterTextChanged
4848
import eu.opencloud.android.BuildConfig
4949
import eu.opencloud.android.MainApp.Companion.accountType
5050
import eu.opencloud.android.R
51+
import eu.opencloud.android.data.authentication.KEY_OIDC_ISSUER
5152
import eu.opencloud.android.data.authentication.KEY_PREFERRED_USERNAME
5253
import eu.opencloud.android.data.authentication.KEY_USER_ID
5354
import eu.opencloud.android.databinding.AccountSetupBinding
@@ -59,7 +60,6 @@ import eu.opencloud.android.domain.exceptions.OpencloudVersionNotSupportedExcept
5960
import eu.opencloud.android.domain.exceptions.SSLErrorCode
6061
import eu.opencloud.android.domain.exceptions.SSLErrorException
6162
import eu.opencloud.android.domain.exceptions.ServerNotReachableException
62-
import eu.opencloud.android.domain.exceptions.StateMismatchException
6363
import eu.opencloud.android.domain.exceptions.UnauthorizedException
6464
import eu.opencloud.android.domain.server.model.ServerInfo
6565
import eu.opencloud.android.extensions.checkPasscodeEnforced
@@ -312,7 +312,13 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
312312
authenticationViewModel.accountDiscovery.observe(this) {
313313
if (it.peekContent() is UIResult.Success) {
314314
notifyDocumentsProviderRoots(applicationContext)
315-
launchFileDisplayActivity()
315+
if (authenticationViewModel.launchedFromDeepLink ||
316+
(isTaskRoot && accountAuthenticatorResponse == null)
317+
) {
318+
launchFileDisplayActivity()
319+
} else {
320+
finish()
321+
}
316322
} else {
317323
binding.authStatusText.run {
318324
text = context.getString(R.string.login_account_preparing)
@@ -559,10 +565,17 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
559565
resultBundle = intent.extras
560566
setResult(Activity.RESULT_OK, intent)
561567

568+
val account = Account(accountName, contextProvider.getString(R.string.account_type))
569+
val am = AccountManager.get(this)
570+
562571
// Store preferred_username from id_token for login_hint on re-login
563-
preferredUsername?.let { prefUsername ->
564-
val account = Account(accountName, contextProvider.getString(R.string.account_type))
565-
AccountManager.get(this).setUserData(account, KEY_PREFERRED_USERNAME, prefUsername)
572+
preferredUsername?.let { am.setUserData(account, KEY_PREFERRED_USERNAME, it) }
573+
574+
// Store OIDC issuer from webfinger so AccountAuthenticator can do OIDC discovery
575+
// against the correct IDP (not the cloud server which may proxy stale config)
576+
val serverInfo = authenticationViewModel.serverInfo.value?.peekContent()?.getStoredData()
577+
if (serverInfo is ServerInfo.OIDCServer) {
578+
am.setUserData(account, KEY_OIDC_ISSUER, serverInfo.oidcServerConfiguration.issuer)
566579
}
567580

568581
authenticationViewModel.discoverAccount(accountName = accountName, discoveryNeeded = loginAction == ACTION_CREATE)
@@ -686,6 +699,10 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
686699
super.onNewIntent(intent)
687700
intent?.let {
688701
Timber.d("onNewIntent received with data: ${it.data}")
702+
if (!::binding.isInitialized) {
703+
Timber.w("onNewIntent received before binding initialized, ignoring OAuth response")
704+
return
705+
}
689706
setIntent(it)
690707
handleGetAuthorizationCodeResponse(it)
691708
}
@@ -696,8 +713,9 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
696713
val state = intent.data?.getQueryParameter("state")
697714

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

9981016
private fun updateOAuthStatusIconAndText(authorizationException: Throwable?) {
1017+
if (!::binding.isInitialized) {
1018+
Timber.w("updateOAuthStatusIconAndText called before binding initialized, ignoring")
1019+
return
1020+
}
9991021
binding.serverStatusText.run {
10001022
setCompoundDrawablesWithIntrinsicBounds(R.drawable.common_error, 0, 0, 0)
10011023
text =

opencloudApp/src/main/java/eu/opencloud/android/presentation/thumbnails/ThumbnailsRequester.kt

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,16 @@ object ThumbnailsRequester : KoinComponent {
188188

189189
override fun intercept(chain: Interceptor.Chain): Response {
190190
val openCloudClient = clientManager.getClientForCoilThumbnails(accountName)
191+
val credentials = openCloudClient.credentials
192+
?: return Response.Builder()
193+
.request(chain.request())
194+
.protocol(okhttp3.Protocol.HTTP_1_1)
195+
.code(401)
196+
.message("No credentials available")
197+
.body(okhttp3.ResponseBody.create(null, ""))
198+
.build()
191199
val requestHeaders = hashMapOf(
192-
AUTHORIZATION_HEADER to openCloudClient.credentials.headerAuth,
200+
AUTHORIZATION_HEADER to credentials.headerAuth,
193201
ACCEPT_ENCODING_HEADER to ACCEPT_ENCODING_IDENTITY,
194202
USER_AGENT_HEADER to SingleSessionManager.getUserAgent(),
195203
OC_X_REQUEST_ID to RandomUtils.generateRandomUUID(),

opencloudData/src/main/java/eu/opencloud/android/data/authentication/AuthenticationConstants.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ const val KEY_FEATURE_SPACES = "KEY_FEATURE_SPACES"
5252
*/
5353
const val KEY_PREFERRED_USERNAME = "oc_preferred_username"
5454

55+
/**
56+
* OIDC issuer URL from webfinger, used for token refresh OIDC discovery
57+
*/
58+
const val KEY_OIDC_ISSUER = "oc_oidc_issuer"
59+
5560
const val KEY_CLIENT_REGISTRATION_CLIENT_ID = "client_id"
5661
const val KEY_CLIENT_REGISTRATION_CLIENT_SECRET = "client_secret"
5762
const val KEY_CLIENT_REGISTRATION_CLIENT_EXPIRATION_DATE = "client_secret_expires_at"

0 commit comments

Comments
 (0)