Skip to content

Commit

Permalink
feat: send clientId and clientSecret in OIDC token requests when …
Browse files Browse the repository at this point in the history
…necessary
  • Loading branch information
JuancaG05 committed Nov 20, 2024
1 parent 80cd855 commit 9c12674
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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);
Expand All @@ -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());
Expand All @@ -375,6 +383,8 @@ private String refreshToken(
tokenEndpoint,
clientAuth,
scope,
clientIdForRequest,
clientSecretForRequest,
refreshToken
);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -609,20 +609,35 @@ 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)

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
)

Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand Down Expand Up @@ -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 ********************************************
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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

Expand All @@ -40,36 +43,43 @@ 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(
tokenEndpoint: String,
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()

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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
Expand All @@ -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
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -16,6 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.owncloud.android.domain.authentication.oauth.model

data class OIDCServerConfiguration(
Expand All @@ -29,4 +32,7 @@ data class OIDCServerConfiguration(
val tokenEndpoint: String,
val tokenEndpointAuthMethodsSupported: List<String>?,
val userInfoEndpoint: String?,
)
) {
fun isTokenEndpointAuthMethodSupportedClientSecretPost(): Boolean =
tokenEndpointAuthMethodsSupported?.any { it == "client_secret_post" } ?: false
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -16,6 +18,7 @@
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/

package com.owncloud.android.domain.authentication.oauth.model

sealed class TokenRequest(
Expand All @@ -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) */
Expand Down

0 comments on commit 9c12674

Please sign in to comment.