diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/AccountAuthenticator.java b/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/AccountAuthenticator.java
index bf32e5a6d23..c597bed732c 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/AccountAuthenticator.java
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/AccountAuthenticator.java
@@ -7,7 +7,7 @@
* @author Juan Carlos Garrote Gascón
*
* Copyright (C) 2012 Bartek Przybylski
- * Copyright (C) 2022 ownCloud GmbH.
+ * Copyright (C) 2024 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@@ -343,6 +343,9 @@ private String refreshToken(
String clientId = accountManager.getUserData(account, KEY_CLIENT_REGISTRATION_CLIENT_ID);
String clientSecret = accountManager.getUserData(account, KEY_CLIENT_REGISTRATION_CLIENT_SECRET);
+ String clientIdForRequest = null;
+ String clientSecretForRequest = null;
+
if (clientId == null) {
Timber.d("Client Id not stored. Let's use the hardcoded one");
clientId = mContext.getString(R.string.oauth2_client_id);
@@ -359,6 +362,11 @@ private String refreshToken(
// Use token endpoint retrieved from oidc discovery
tokenEndpoint = oidcServerConfigurationUseCaseResult.getDataOrNull().getTokenEndpoint();
+ if (oidcServerConfigurationUseCaseResult.getDataOrNull() != null &&
+ oidcServerConfigurationUseCaseResult.getDataOrNull().isTokenEndpointAuthMethodSupportedClientSecretPost()) {
+ clientIdForRequest = clientId;
+ clientSecretForRequest = clientSecret;
+ }
} else {
Timber.d("OIDC Discovery failed. Server discovery info: [ %s ]",
oidcServerConfigurationUseCaseResult.getThrowableOrNull().toString());
@@ -375,6 +383,8 @@ private String refreshToken(
tokenEndpoint,
clientAuth,
scope,
+ clientIdForRequest,
+ clientSecretForRequest,
refreshToken
);
diff --git a/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/LoginActivity.kt b/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/LoginActivity.kt
index 0a66264e815..4720c437baa 100644
--- a/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/LoginActivity.kt
+++ b/owncloudApp/src/main/java/com/owncloud/android/presentation/authentication/LoginActivity.kt
@@ -609,9 +609,22 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
}
// Use oidc discovery one, or build an oauth endpoint using serverBaseUrl + Setup string.
- val tokenEndPoint = when (val serverInfo = authenticationViewModel.serverInfo.value?.peekContent()?.getStoredData()) {
- is ServerInfo.OIDCServer -> serverInfo.oidcServerConfiguration.tokenEndpoint
- else -> "$serverBaseUrl${File.separator}${contextProvider.getString(R.string.oauth2_url_endpoint_access)}"
+ val tokenEndPoint: String
+
+ var clientId: String? = null
+ var clientSecret: String? = null
+
+ when (val serverInfo = authenticationViewModel.serverInfo.value?.peekContent()?.getStoredData()) {
+ is ServerInfo.OIDCServer -> {
+ tokenEndPoint = serverInfo.oidcServerConfiguration.tokenEndpoint
+ if (serverInfo.oidcServerConfiguration.isTokenEndpointAuthMethodSupportedClientSecretPost()) {
+ clientId = clientRegistrationInfo?.clientId ?: contextProvider.getString(R.string.oauth2_client_id)
+ clientSecret = clientRegistrationInfo?.clientSecret ?: contextProvider.getString(R.string.oauth2_client_secret)
+ }
+ }
+ else -> {
+ tokenEndPoint = "$serverBaseUrl${File.separator}${contextProvider.getString(R.string.oauth2_url_endpoint_access)}"
+ }
}
val scope = resources.getString(R.string.oauth2_openid_scope)
@@ -619,10 +632,12 @@ class LoginActivity : AppCompatActivity(), SslUntrustedCertDialog.OnSslUntrusted
val requestToken = TokenRequest.AccessToken(
baseUrl = serverBaseUrl,
tokenEndpoint = tokenEndPoint,
- authorizationCode = authorizationCode,
- redirectUri = OAuthUtils.buildRedirectUri(applicationContext).toString(),
clientAuth = clientAuth,
scope = scope,
+ clientId = clientId,
+ clientSecret = clientSecret,
+ authorizationCode = authorizationCode,
+ redirectUri = OAuthUtils.buildRedirectUri(applicationContext).toString(),
codeVerifier = authenticationViewModel.codeVerifier
)
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpConstants.java b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpConstants.java
index 48fcdcee2d7..ce889c7319a 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpConstants.java
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/common/http/HttpConstants.java
@@ -1,5 +1,5 @@
/* ownCloud Android Library is available under MIT license
- * Copyright (C) 2020 ownCloud GmbH.
+ * Copyright (C) 2024 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -59,6 +59,8 @@ public class HttpConstants {
public static final String OAUTH_HEADER_REFRESH_TOKEN = "refresh_token";
public static final String OAUTH_HEADER_CODE_VERIFIER = "code_verifier";
public static final String OAUTH_HEADER_SCOPE = "scope";
+ public static final String OAUTH_BODY_CLIENT_ID = "client_id";
+ public static final String OAUTH_BODY_CLIENT_SECRET = "client_secret";
/***********************************************************************************************************
************************************************ CONTENT TYPES ********************************************
diff --git a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/oauth/params/TokenRequestParams.kt b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/oauth/params/TokenRequestParams.kt
index 6fb8919df7c..7169b75bb27 100644
--- a/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/oauth/params/TokenRequestParams.kt
+++ b/owncloudComLibrary/src/main/java/com/owncloud/android/lib/resources/oauth/params/TokenRequestParams.kt
@@ -1,6 +1,6 @@
/* ownCloud Android Library is available under MIT license
*
- * Copyright (C) 2020 ownCloud GmbH.
+ * Copyright (C) 2024 ownCloud GmbH.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
@@ -21,6 +21,7 @@
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
+
package com.owncloud.android.lib.resources.oauth.params
import com.owncloud.android.lib.common.http.HttpConstants
@@ -32,6 +33,8 @@ sealed class TokenRequestParams(
val clientAuth: String,
val grantType: String,
val scope: String,
+ val clientId: String?,
+ val clientSecret: String?,
) {
abstract fun toRequestBody(): RequestBody
@@ -40,19 +43,24 @@ sealed class TokenRequestParams(
clientAuth: String,
grantType: String,
scope: String,
+ clientId: String?,
+ clientSecret: String?,
val authorizationCode: String,
val redirectUri: String,
val codeVerifier: String,
- ) : TokenRequestParams(tokenEndpoint, clientAuth, grantType, scope) {
+ ) : TokenRequestParams(tokenEndpoint, clientAuth, grantType, scope, clientId, clientSecret) {
override fun toRequestBody(): RequestBody =
- FormBody.Builder()
- .add(HttpConstants.OAUTH_HEADER_AUTHORIZATION_CODE, authorizationCode)
- .add(HttpConstants.OAUTH_HEADER_GRANT_TYPE, grantType)
- .add(HttpConstants.OAUTH_HEADER_REDIRECT_URI, redirectUri)
- .add(HttpConstants.OAUTH_HEADER_CODE_VERIFIER, codeVerifier)
- .add(HttpConstants.OAUTH_HEADER_SCOPE, scope)
- .build()
+ FormBody.Builder().apply {
+ add(HttpConstants.OAUTH_HEADER_AUTHORIZATION_CODE, authorizationCode)
+ add(HttpConstants.OAUTH_HEADER_GRANT_TYPE, grantType)
+ add(HttpConstants.OAUTH_HEADER_REDIRECT_URI, redirectUri)
+ add(HttpConstants.OAUTH_HEADER_CODE_VERIFIER, codeVerifier)
+ add(HttpConstants.OAUTH_HEADER_SCOPE, scope)
+ if (clientId != null) add(HttpConstants.OAUTH_BODY_CLIENT_ID, clientId)
+ if (clientSecret != null) add(HttpConstants.OAUTH_BODY_CLIENT_SECRET, clientSecret)
+ }.build()
+
}
class RefreshToken(
@@ -60,16 +68,18 @@ sealed class TokenRequestParams(
clientAuth: String,
grantType: String,
scope: String,
+ clientId: String?,
+ clientSecret: String?,
val refreshToken: String? = null
- ) : TokenRequestParams(tokenEndpoint, clientAuth, grantType, scope) {
+ ) : TokenRequestParams(tokenEndpoint, clientAuth, grantType, scope, clientId, clientSecret) {
override fun toRequestBody(): RequestBody =
FormBody.Builder().apply {
add(HttpConstants.OAUTH_HEADER_GRANT_TYPE, grantType)
add(HttpConstants.OAUTH_HEADER_SCOPE, scope)
- if (!refreshToken.isNullOrBlank()) {
- add(HttpConstants.OAUTH_HEADER_REFRESH_TOKEN, refreshToken)
- }
+ if (!refreshToken.isNullOrBlank()) add(HttpConstants.OAUTH_HEADER_REFRESH_TOKEN, refreshToken)
+ if (clientId != null) add(HttpConstants.OAUTH_BODY_CLIENT_ID, clientId)
+ if (clientSecret != null) add(HttpConstants.OAUTH_BODY_CLIENT_SECRET, clientSecret)
}.build()
}
diff --git a/owncloudData/src/main/java/com/owncloud/android/data/oauth/datasources/implementation/OCRemoteOAuthDataSource.kt b/owncloudData/src/main/java/com/owncloud/android/data/oauth/datasources/implementation/OCRemoteOAuthDataSource.kt
index 1cc057d611a..351f0ac80ba 100644
--- a/owncloudData/src/main/java/com/owncloud/android/data/oauth/datasources/implementation/OCRemoteOAuthDataSource.kt
+++ b/owncloudData/src/main/java/com/owncloud/android/data/oauth/datasources/implementation/OCRemoteOAuthDataSource.kt
@@ -2,7 +2,9 @@
* ownCloud Android client application
*
* @author Abel García de Prada
- * Copyright (C) 2020 ownCloud GmbH.
+ * @author Juan Carlos Garrote Gascón
+ *
+ * Copyright (C) 2024 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@@ -103,6 +105,8 @@ class OCRemoteOAuthDataSource(
authorizationCode = this.authorizationCode,
grantType = this.grantType,
scope = this.scope,
+ clientId = this.clientId,
+ clientSecret = this.clientSecret,
redirectUri = this.redirectUri,
clientAuth = this.clientAuth,
codeVerifier = this.codeVerifier
@@ -112,6 +116,8 @@ class OCRemoteOAuthDataSource(
tokenEndpoint = this.tokenEndpoint,
grantType = this.grantType,
scope = this.scope,
+ clientId = this.clientId,
+ clientSecret = this.clientSecret,
clientAuth = this.clientAuth,
refreshToken = this.refreshToken
)
diff --git a/owncloudData/src/test/java/com/owncloud/android/data/oauth/RemoteOAuthUtils.kt b/owncloudData/src/test/java/com/owncloud/android/data/oauth/RemoteOAuthUtils.kt
index 6f6f09541a1..dc84a584620 100644
--- a/owncloudData/src/test/java/com/owncloud/android/data/oauth/RemoteOAuthUtils.kt
+++ b/owncloudData/src/test/java/com/owncloud/android/data/oauth/RemoteOAuthUtils.kt
@@ -48,6 +48,8 @@ val OC_REMOTE_TOKEN_REQUEST_PARAMS_ACCESS = TokenRequestParams.Authorization(
clientAuth = OC_TOKEN_REQUEST_ACCESS.clientAuth,
grantType = OC_TOKEN_REQUEST_ACCESS.grantType,
scope = OC_TOKEN_REQUEST_ACCESS.scope,
+ clientId = null,
+ clientSecret = null,
authorizationCode = OC_TOKEN_REQUEST_ACCESS.authorizationCode,
redirectUri = OC_TOKEN_REQUEST_ACCESS.redirectUri,
codeVerifier = OC_TOKEN_REQUEST_ACCESS.codeVerifier
@@ -58,6 +60,8 @@ val OC_REMOTE_TOKEN_REQUEST_PARAMS_REFRESH = TokenRequestParams.RefreshToken(
clientAuth = OC_TOKEN_REQUEST_REFRESH.clientAuth,
grantType = OC_TOKEN_REQUEST_REFRESH.grantType,
scope = OC_TOKEN_REQUEST_REFRESH.scope,
+ clientId = null,
+ clientSecret = null,
refreshToken = OC_TOKEN_REQUEST_REFRESH.refreshToken
)
diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/OIDCServerConfiguration.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/OIDCServerConfiguration.kt
index 5c8de9722ef..1c0d22405ff 100644
--- a/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/OIDCServerConfiguration.kt
+++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/OIDCServerConfiguration.kt
@@ -2,7 +2,9 @@
* ownCloud Android client application
*
* @author Abel García de Prada
- * Copyright (C) 2020 ownCloud GmbH.
+ * @author Juan Carlos Garrote Gascón
+ *
+ * Copyright (C) 2024 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@@ -16,6 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
package com.owncloud.android.domain.authentication.oauth.model
data class OIDCServerConfiguration(
@@ -29,4 +32,7 @@ data class OIDCServerConfiguration(
val tokenEndpoint: String,
val tokenEndpointAuthMethodsSupported: List?,
val userInfoEndpoint: String?,
-)
+) {
+ fun isTokenEndpointAuthMethodSupportedClientSecretPost(): Boolean =
+ tokenEndpointAuthMethodsSupported?.any { it == "client_secret_post" } ?: false
+}
diff --git a/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/TokenRequest.kt b/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/TokenRequest.kt
index 1ac098509d9..a8e814dc3ec 100644
--- a/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/TokenRequest.kt
+++ b/owncloudDomain/src/main/java/com/owncloud/android/domain/authentication/oauth/model/TokenRequest.kt
@@ -2,7 +2,9 @@
* ownCloud Android client application
*
* @author Abel García de Prada
- * Copyright (C) 2020 ownCloud GmbH.
+ * @author Juan Carlos Garrote Gascón
+ *
+ * Copyright (C) 2024 ownCloud GmbH.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2,
@@ -16,6 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
+
package com.owncloud.android.domain.authentication.oauth.model
sealed class TokenRequest(
@@ -24,24 +27,30 @@ sealed class TokenRequest(
val clientAuth: String,
val grantType: String,
val scope: String,
+ val clientId: String?,
+ val clientSecret: String?,
) {
class AccessToken(
baseUrl: String,
tokenEndpoint: String,
clientAuth: String,
scope: String,
+ clientId: String? = null,
+ clientSecret: String? = null,
val authorizationCode: String,
val redirectUri: String,
val codeVerifier: String
- ) : TokenRequest(baseUrl, tokenEndpoint, clientAuth, GrantType.ACCESS_TOKEN.string, scope)
+ ) : TokenRequest(baseUrl, tokenEndpoint, clientAuth, GrantType.ACCESS_TOKEN.string, scope, clientId, clientSecret)
class RefreshToken(
baseUrl: String,
tokenEndpoint: String,
clientAuth: String,
scope: String,
+ clientId: String? = null,
+ clientSecret: String? = null,
val refreshToken: String? = null
- ) : TokenRequest(baseUrl, tokenEndpoint, clientAuth, GrantType.REFRESH_TOKEN.string, scope)
+ ) : TokenRequest(baseUrl, tokenEndpoint, clientAuth, GrantType.REFRESH_TOKEN.string, scope, clientId, clientSecret)
enum class GrantType(val string: String) {
/** Request access token. [More info](https://tools.ietf.org/html/rfc6749#section-4.1.3) */