Skip to content

Commit

Permalink
Little refactor and new unit tests
Browse files Browse the repository at this point in the history
  • Loading branch information
abelgardep committed Feb 9, 2021
1 parent 6b87066 commit f0c77b0
Show file tree
Hide file tree
Showing 17 changed files with 280 additions and 72 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,17 @@ import com.owncloud.android.data.authentication.QUERY_PARAMETER_CLIENT_ID
import com.owncloud.android.data.authentication.QUERY_PARAMETER_REDIRECT_URI
import com.owncloud.android.data.authentication.QUERY_PARAMETER_RESPONSE_TYPE
import com.owncloud.android.data.authentication.QUERY_PARAMETER_SCOPE
import com.owncloud.android.domain.authentication.oauth.RegisterClientUseCase
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationRequest
import java.net.URLEncoder

class OAuthUtils {
companion object {

fun composeClientRegistrationUseCaseParams(
fun buildClientRegistrationRequest(
registrationEndpoint: String,
context: Context
): RegisterClientUseCase.Params =
RegisterClientUseCase.Params(
): ClientRegistrationRequest =
ClientRegistrationRequest(
registrationEndpoint = registrationEndpoint,
clientName = MainApp.userAgent,
redirectUris = listOf(buildRedirectUri(context).toString())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

package com.owncloud.android.dependecyinjection

import com.owncloud.android.presentation.viewmodels.oauth.OAuthViewModel
import com.owncloud.android.presentation.viewmodels.authentication.OCAuthenticationViewModel
import com.owncloud.android.presentation.viewmodels.capabilities.OCCapabilityViewModel
import com.owncloud.android.presentation.viewmodels.drawer.DrawerViewModel
import com.owncloud.android.presentation.viewmodels.oauth.OAuthViewModel
import com.owncloud.android.presentation.viewmodels.sharing.OCShareViewModel
import org.koin.androidx.viewmodel.dsl.viewModel
import org.koin.dsl.module
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,8 @@ class OAuthViewModel(
fun registerClient(
registrationEndpoint: String
) {
val registerUseCaseParams = OAuthUtils.composeClientRegistrationUseCaseParams(
registrationEndpoint,
val registrationRequest = OAuthUtils.buildClientRegistrationRequest(
registrationEndpoint = registrationEndpoint,
MainApp.appContext
)

Expand All @@ -72,7 +72,7 @@ class OAuthViewModel(
showLoading = false,
liveData = _registerClient,
useCase = registerClientUseCase,
useCaseParams = registerUseCaseParams
useCaseParams = RegisterClientUseCase.Params(registrationRequest)
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ package com.owncloud.android.data.oauth
import com.owncloud.android.data.oauth.datasource.RemoteOAuthDataSource
import com.owncloud.android.domain.authentication.oauth.OAuthRepository
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationInfo
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationRequest
import com.owncloud.android.domain.authentication.oauth.model.OIDCServerConfiguration
import com.owncloud.android.domain.authentication.oauth.model.TokenRequest
import com.owncloud.android.domain.authentication.oauth.model.TokenResponse
Expand All @@ -34,18 +35,6 @@ class OAuthRepositoryImpl(
override fun performTokenRequest(tokenRequest: TokenRequest): TokenResponse =
oidcRemoteOAuthDataSource.performTokenRequest(tokenRequest)

override fun registerClient(
registrationEndpoint: String,
clientName: String,
redirectUris: List<String>,
tokenEndpointAuthMethod: String,
applicationType: String
): ClientRegistrationInfo =
oidcRemoteOAuthDataSource.registerClient(
registrationEndpoint = registrationEndpoint,
clientName = clientName,
redirectUris = redirectUris,
tokenEndpointAuthMethod = tokenEndpointAuthMethod,
applicationType = applicationType
)
override fun registerClient(clientRegistrationRequest: ClientRegistrationRequest): ClientRegistrationInfo =
oidcRemoteOAuthDataSource.registerClient(clientRegistrationRequest)
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.owncloud.android.data.oauth.datasource

import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationInfo
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationRequest
import com.owncloud.android.domain.authentication.oauth.model.OIDCServerConfiguration
import com.owncloud.android.domain.authentication.oauth.model.TokenRequest
import com.owncloud.android.domain.authentication.oauth.model.TokenResponse
Expand All @@ -27,12 +28,6 @@ interface RemoteOAuthDataSource {
fun performOIDCDiscovery(baseUrl: String): OIDCServerConfiguration
fun performTokenRequest(tokenRequest: TokenRequest): TokenResponse

fun registerClient(
registrationEndpoint: String,
clientName: String,
redirectUris: List<String>,
tokenEndpointAuthMethod: String,
applicationType: String
): ClientRegistrationInfo
fun registerClient(clientRegistrationRequest: ClientRegistrationRequest): ClientRegistrationInfo

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import com.owncloud.android.data.oauth.mapper.RemoteOIDCDiscoveryMapper
import com.owncloud.android.data.oauth.mapper.RemoteTokenRequestMapper
import com.owncloud.android.data.oauth.mapper.RemoteTokenResponseMapper
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationInfo
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationRequest
import com.owncloud.android.domain.authentication.oauth.model.OIDCServerConfiguration
import com.owncloud.android.domain.authentication.oauth.model.TokenRequest
import com.owncloud.android.domain.authentication.oauth.model.TokenResponse
Expand Down Expand Up @@ -65,24 +66,19 @@ class RemoteOAuthDataSourceImpl(
return remoteTokenResponseMapper.toModel(tokenResponse)!!
}

override fun registerClient(
registrationEndpoint: String,
clientName: String,
redirectUris: List<String>,
tokenEndpointAuthMethod: String,
applicationType: String
): ClientRegistrationInfo {
val ownCloudClient = clientManager.getClientForUnExistingAccount(registrationEndpoint, false)
override fun registerClient(clientRegistrationRequest: ClientRegistrationRequest): ClientRegistrationInfo {
val ownCloudClient =
clientManager.getClientForUnExistingAccount(clientRegistrationRequest.registrationEndpoint, false)

val remoteClientRegistrationInfo = executeRemoteOperation {
oidcService.registerClientWithRegistrationEndpoint(
ownCloudClient = ownCloudClient,
clientRegistrationParams = ClientRegistrationParams(
registrationEndpoint = registrationEndpoint,
clientName = clientName,
redirectUris = redirectUris,
tokenEndpointAuthMethod = tokenEndpointAuthMethod,
applicationType = applicationType
registrationEndpoint = clientRegistrationRequest.registrationEndpoint,
clientName = clientRegistrationRequest.clientName,
redirectUris = clientRegistrationRequest.redirectUris,
tokenEndpointAuthMethod = clientRegistrationRequest.tokenEndpointAuthMethod,
applicationType = clientRegistrationRequest.applicationType
)
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ package com.owncloud.android.data.oauth
import com.owncloud.android.data.oauth.datasource.RemoteOAuthDataSource
import com.owncloud.android.domain.authentication.oauth.OAuthRepository
import com.owncloud.android.testutil.OC_SERVER_INFO
import com.owncloud.android.testutil.oauth.OC_CLIENT_REGISTRATION
import com.owncloud.android.testutil.oauth.OC_CLIENT_REGISTRATION_REQUEST
import com.owncloud.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
import com.owncloud.android.testutil.oauth.OC_TOKEN_REQUEST_ACCESS
import com.owncloud.android.testutil.oauth.OC_TOKEN_RESPONSE
Expand Down Expand Up @@ -69,4 +71,22 @@ class OAuthRepositoryTest {

oAuthRepository.performTokenRequest(OC_TOKEN_REQUEST_ACCESS)
}

@Test
fun `register client - ok`() {
every { remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST) } returns OC_CLIENT_REGISTRATION

oAuthRepository.registerClient(OC_CLIENT_REGISTRATION_REQUEST)

verify(exactly = 1) {
remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST)
}
}

@Test(expected = Exception::class)
fun `register client - ko`() {
every { remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST) } throws Exception()

remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,9 +18,13 @@
*/
package com.owncloud.android.data.oauth

import com.owncloud.android.lib.resources.oauth.params.ClientRegistrationParams
import com.owncloud.android.lib.resources.oauth.params.TokenRequestParams
import com.owncloud.android.lib.resources.oauth.responses.ClientRegistrationResponse
import com.owncloud.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
import com.owncloud.android.lib.resources.oauth.responses.TokenResponse
import com.owncloud.android.testutil.oauth.OC_CLIENT_REGISTRATION
import com.owncloud.android.testutil.oauth.OC_CLIENT_REGISTRATION_REQUEST
import com.owncloud.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
import com.owncloud.android.testutil.oauth.OC_TOKEN_REQUEST_ACCESS
import com.owncloud.android.testutil.oauth.OC_TOKEN_REQUEST_REFRESH
Expand Down Expand Up @@ -63,3 +67,18 @@ val OC_REMOTE_TOKEN_RESPONSE = TokenResponse(
scope = OC_TOKEN_RESPONSE.scope,
additionalParameters = OC_TOKEN_RESPONSE.additionalParameters
)

val OC_REMOTE_CLIENT_REGISTRATION_PARAMS = ClientRegistrationParams(
registrationEndpoint = OC_CLIENT_REGISTRATION_REQUEST.registrationEndpoint,
clientName = OC_CLIENT_REGISTRATION_REQUEST.clientName,
redirectUris = OC_CLIENT_REGISTRATION_REQUEST.redirectUris,
tokenEndpointAuthMethod = OC_CLIENT_REGISTRATION_REQUEST.tokenEndpointAuthMethod,
applicationType = OC_CLIENT_REGISTRATION_REQUEST.applicationType
)

val OC_REMOTE_CLIENT_REGISTRATION_RESPONSE = ClientRegistrationResponse(
clientId = OC_CLIENT_REGISTRATION.clientId,
clientSecret = OC_CLIENT_REGISTRATION.clientSecret,
clientIdIssuedAt = OC_CLIENT_REGISTRATION.clientIdIssuedAt,
clientSecretExpiration = OC_CLIENT_REGISTRATION.clientSecretExpiration
)
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
package com.owncloud.android.data.oauth.datasource

import com.owncloud.android.data.ClientManager
import com.owncloud.android.data.oauth.OC_REMOTE_CLIENT_REGISTRATION_PARAMS
import com.owncloud.android.data.oauth.OC_REMOTE_CLIENT_REGISTRATION_RESPONSE
import com.owncloud.android.data.oauth.OC_REMOTE_OIDC_DISCOVERY_RESPONSE
import com.owncloud.android.data.oauth.OC_REMOTE_TOKEN_REQUEST_PARAMS_ACCESS
import com.owncloud.android.data.oauth.OC_REMOTE_TOKEN_RESPONSE
Expand All @@ -30,10 +32,13 @@ import com.owncloud.android.data.oauth.mapper.RemoteTokenRequestMapper
import com.owncloud.android.data.oauth.mapper.RemoteTokenResponseMapper
import com.owncloud.android.lib.common.OwnCloudClient
import com.owncloud.android.lib.common.operations.RemoteOperationResult
import com.owncloud.android.lib.resources.oauth.responses.ClientRegistrationResponse
import com.owncloud.android.lib.resources.oauth.responses.OIDCDiscoveryResponse
import com.owncloud.android.lib.resources.oauth.responses.TokenResponse
import com.owncloud.android.lib.resources.oauth.services.OIDCService
import com.owncloud.android.testutil.OC_BASE_URL
import com.owncloud.android.testutil.oauth.OC_CLIENT_REGISTRATION
import com.owncloud.android.testutil.oauth.OC_CLIENT_REGISTRATION_REQUEST
import com.owncloud.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
import com.owncloud.android.testutil.oauth.OC_TOKEN_REQUEST_ACCESS
import com.owncloud.android.testutil.oauth.OC_TOKEN_RESPONSE
Expand Down Expand Up @@ -118,4 +123,28 @@ class RemoteOAuthDataSourceTest {

remoteOAuthDataSource.performTokenRequest(OC_TOKEN_REQUEST_ACCESS)
}

@Test
fun `register client - ok`() {
val clientRegistrationResponse: RemoteOperationResult<ClientRegistrationResponse> =
createRemoteOperationResultMock(data = OC_REMOTE_CLIENT_REGISTRATION_RESPONSE, isSuccess = true)

every {
oidcService.registerClientWithRegistrationEndpoint(ocClientMocked, any())
} returns clientRegistrationResponse

val clientRegistrationInfo = remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST)

assertNotNull(clientRegistrationInfo)
assertEquals(OC_CLIENT_REGISTRATION, clientRegistrationInfo)
}

@Test(expected = Exception::class)
fun `register client - ko`() {
every {
oidcService.registerClientWithRegistrationEndpoint(ocClientMocked, OC_REMOTE_CLIENT_REGISTRATION_PARAMS)
} throws Exception()

remoteOAuthDataSource.registerClient(OC_CLIENT_REGISTRATION_REQUEST)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/**
* ownCloud Android client application
*
* @author Abel García de Prada
* Copyright (C) 2021 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,
* as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* 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.data.oauth.mapper

import com.owncloud.android.data.oauth.OC_REMOTE_CLIENT_REGISTRATION_RESPONSE
import com.owncloud.android.data.oauth.OC_REMOTE_OIDC_DISCOVERY_RESPONSE
import com.owncloud.android.testutil.oauth.OC_CLIENT_REGISTRATION
import com.owncloud.android.testutil.oauth.OC_OIDC_SERVER_CONFIGURATION
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertNull
import org.junit.Test

class RemoteClientRegistrationMapperTest {

private val remoteClientRegistrationInfoMapper = RemoteClientRegistrationInfoMapper()

@Test
fun `to model - ok - null`() {
assertNull(remoteClientRegistrationInfoMapper.toModel(null))
}

@Test
fun `to model - ok`() {
assertNotNull(OC_REMOTE_CLIENT_REGISTRATION_RESPONSE)

val clientRegistrationInfo = remoteClientRegistrationInfoMapper.toModel(OC_REMOTE_CLIENT_REGISTRATION_RESPONSE)

assertNotNull(clientRegistrationInfo)
assertEquals(OC_CLIENT_REGISTRATION, clientRegistrationInfo)
}

@Test
fun `to remote - ok - null`() {
assertNull(remoteClientRegistrationInfoMapper.toRemote(null))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
package com.owncloud.android.domain.authentication.oauth

import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationInfo
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationRequest
import com.owncloud.android.domain.authentication.oauth.model.OIDCServerConfiguration
import com.owncloud.android.domain.authentication.oauth.model.TokenRequest
import com.owncloud.android.domain.authentication.oauth.model.TokenResponse
Expand All @@ -27,11 +28,5 @@ interface OAuthRepository {
fun performOIDCDiscovery(baseUrl: String): OIDCServerConfiguration
fun performTokenRequest(tokenRequest: TokenRequest): TokenResponse

fun registerClient(
registrationEndpoint: String,
clientName: String,
redirectUris: List<String>,
tokenEndpointAuthMethod: String,
applicationType: String
): ClientRegistrationInfo
fun registerClient(clientRegistrationRequest: ClientRegistrationRequest): ClientRegistrationInfo
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,35 +20,16 @@ package com.owncloud.android.domain.authentication.oauth

import com.owncloud.android.domain.BaseUseCaseWithResult
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationInfo
import com.owncloud.android.domain.authentication.oauth.model.ClientRegistrationRequest

class RegisterClientUseCase(
private val oAuthRepository: OAuthRepository
) : BaseUseCaseWithResult<ClientRegistrationInfo, RegisterClientUseCase.Params>() {

override fun run(params: Params): ClientRegistrationInfo =
oAuthRepository.registerClient(
registrationEndpoint = params.registrationEndpoint,
clientName = params.clientName,
redirectUris = params.redirectUris,
tokenEndpointAuthMethod = params.tokenEndpointAuthMethod,
applicationType = params.applicationType
)
oAuthRepository.registerClient(clientRegistrationRequest = params.clientRegistrationRequest)

data class Params(
val registrationEndpoint: String,
val clientName: String,
val redirectUris: List<String>,
val tokenEndpointAuthMethod: String = CLIENT_REGISTRATION_SECRET_BASIC,
val applicationType: String = CLIENT_REGISTRATION_APPLICATION_TYPE
val clientRegistrationRequest: ClientRegistrationRequest
)

companion object {
/**
* The client uses HTTP Basic as defined in OAuth 2.0, Section 2.3.1.
* https://tools.ietf.org/html/rfc7591#section-2.3.1
* Use this auth method for the moment. We should check if it is allowed in the OIDC Discovery.
*/
private const val CLIENT_REGISTRATION_SECRET_BASIC = "client_secret_basic"
private const val CLIENT_REGISTRATION_APPLICATION_TYPE = "native"
}
}
Loading

0 comments on commit f0c77b0

Please sign in to comment.