Add AuthorizationServiceProvider

pull/1244/head
Alex Baker 5 years ago
parent f126e7e462
commit 13d10eb203

@ -4,19 +4,17 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import androidx.browser.customtabs.CustomTabsIntent import androidx.browser.customtabs.CustomTabsIntent
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import net.openid.appauth.* import net.openid.appauth.*
import net.openid.appauth.AuthorizationService import net.openid.appauth.AuthorizationService
import net.openid.appauth.browser.AnyBrowserMatcher import net.openid.appauth.browser.AnyBrowserMatcher
import javax.inject.Inject
import kotlin.coroutines.suspendCoroutine import kotlin.coroutines.suspendCoroutine
class AuthorizationService @Inject constructor( class AuthorizationService constructor(
@ApplicationContext context: Context, context: Context,
private val authStateManager: AuthStateManager, private val authStateManager: AuthStateManager,
configuration: Configuration val configuration: Configuration
) { ) {
private val authorizationService = AuthorizationService( private val authorizationService = AuthorizationService(
context, context,

@ -0,0 +1,21 @@
package org.tasks.auth
import android.content.Context
import dagger.hilt.android.qualifiers.ApplicationContext
import org.tasks.auth.Configuration.Companion.GOOGLE_CONFIG
import javax.inject.Inject
class AuthorizationServiceProvider @Inject constructor(
@ApplicationContext context: Context,
authStateManager: AuthStateManager
){
val google = AuthorizationService(
context,
authStateManager,
Configuration(context, GOOGLE_CONFIG)
)
fun dispose() {
google.dispose()
}
}

@ -17,7 +17,6 @@ import android.content.Context
import android.content.Intent import android.content.Intent
import android.net.Uri import android.net.Uri
import android.text.TextUtils import android.text.TextUtils
import dagger.hilt.android.qualifiers.ApplicationContext
import net.openid.appauth.connectivity.ConnectionBuilder import net.openid.appauth.connectivity.ConnectionBuilder
import net.openid.appauth.connectivity.DefaultConnectionBuilder import net.openid.appauth.connectivity.DefaultConnectionBuilder
import okio.Buffer import okio.Buffer
@ -28,17 +27,15 @@ import org.json.JSONObject
import org.tasks.R import org.tasks.R
import java.io.IOException import java.io.IOException
import java.nio.charset.StandardCharsets import java.nio.charset.StandardCharsets
import javax.inject.Inject
import javax.inject.Singleton
/** /**
* Reads and validates the demo app configuration from `res/raw/auth_config.json`. Configuration * Reads and validates the app configuration from `authConfig`. Configuration
* changes are detected by comparing the hash of the last known configuration to the read * changes are detected by comparing the hash of the last known configuration to the read
* configuration. When a configuration change is detected, the app state is reset. * configuration. When a configuration change is detected, the app state is reset.
*/ */
@Singleton class Configuration constructor(
class Configuration @Inject constructor( private val context: Context,
@ApplicationContext private val context: Context private val authConfig: Int
) { ) {
private val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE) private val prefs = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
private var configJson: JSONObject? = null private var configJson: JSONObject? = null
@ -100,7 +97,7 @@ class Configuration @Inject constructor(
@Throws(InvalidConfigurationException::class) @Throws(InvalidConfigurationException::class)
private fun readConfiguration() { private fun readConfiguration() {
val configSource = context.resources.openRawResource(R.raw.auth_config).source().buffer() val configSource = context.resources.openRawResource(authConfig).source().buffer()
val configData = Buffer() val configData = Buffer()
configJson = try { configJson = try {
configSource.readAll(configData) configSource.readAll(configData)
@ -209,6 +206,7 @@ class Configuration @Inject constructor(
companion object { companion object {
private const val PREFS_NAME = "config" private const val PREFS_NAME = "config"
private const val KEY_LAST_HASH = "lastHash" private const val KEY_LAST_HASH = "lastHash"
const val GOOGLE_CONFIG = R.raw.google_config
} }
init { init {

@ -41,8 +41,7 @@ import javax.inject.Inject
/** /**
* Demonstrates the usage of the AppAuth to authorize a user with an OAuth2 / OpenID Connect * Demonstrates the usage of the AppAuth to authorize a user with an OAuth2 / OpenID Connect
* provider. Based on the configuration provided in `res/raw/auth_config.json`, the code * provider
* contained here will:
* *
* - Retrieve an OpenID Connect discovery document for the provider, or use a local static * - Retrieve an OpenID Connect discovery document for the provider, or use a local static
* configuration. * configuration.
@ -51,9 +50,8 @@ import javax.inject.Inject
*/ */
@AndroidEntryPoint @AndroidEntryPoint
class SignInActivity : InjectingAppCompatActivity(), PurchaseDialog.PurchaseHandler { class SignInActivity : InjectingAppCompatActivity(), PurchaseDialog.PurchaseHandler {
@Inject lateinit var authService: AuthorizationService @Inject lateinit var authorizationServiceProvider: AuthorizationServiceProvider
@Inject lateinit var authStateManager: AuthStateManager @Inject lateinit var authStateManager: AuthStateManager
@Inject lateinit var configuration: Configuration
@Inject lateinit var themeColor: ThemeColor @Inject lateinit var themeColor: ThemeColor
@Inject lateinit var inventory: Inventory @Inject lateinit var inventory: Inventory
@ -65,11 +63,17 @@ class SignInActivity : InjectingAppCompatActivity(), PurchaseDialog.PurchaseHand
private var mAuthIntentLatch = CountDownLatch(1) private var mAuthIntentLatch = CountDownLatch(1)
private val mExecutor: ExecutorService = newSingleThreadExecutor() private val mExecutor: ExecutorService = newSingleThreadExecutor()
lateinit var authService: AuthorizationService
lateinit var configuration: Configuration
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
viewModel.error.observe(this, this::handleError) viewModel.error.observe(this, this::handleError)
authService = authorizationServiceProvider.google
configuration = authService.configuration
if (authStateManager.current.isAuthorized && if (authStateManager.current.isAuthorized &&
!configuration.hasConfigurationChanged()) { !configuration.hasConfigurationChanged()) {
Timber.i("User is already authenticated, signing out") Timber.i("User is already authenticated, signing out")
@ -155,7 +159,7 @@ class SignInActivity : InjectingAppCompatActivity(), PurchaseDialog.PurchaseHand
// if we are not using discovery, build the authorization service configuration directly // if we are not using discovery, build the authorization service configuration directly
// from the static configuration values. // from the static configuration values.
if (configuration.discoveryUri == null) { if (configuration.discoveryUri == null) {
Timber.i("Creating auth config from res/raw/auth_config.json") Timber.i("Creating auth config")
val config = AuthorizationServiceConfiguration( val config = AuthorizationServiceConfiguration(
configuration.authEndpointUri!!, configuration.authEndpointUri!!,
configuration.tokenEndpointUri!!, configuration.tokenEndpointUri!!,

@ -20,7 +20,7 @@ import timber.log.Timber
class SignInViewModel @ViewModelInject constructor( class SignInViewModel @ViewModelInject constructor(
@ApplicationContext private val context: Context, @ApplicationContext private val context: Context,
private val authStateManager: AuthStateManager, private val authStateManager: AuthStateManager,
private val authorizationService: AuthorizationService, private val authorizationServiceProvider: AuthorizationServiceProvider,
private val provider: CaldavClientProvider, private val provider: CaldavClientProvider,
private val caldavDao: CaldavDao private val caldavDao: CaldavDao
) : ViewModel() { ) : ViewModel() {
@ -88,12 +88,14 @@ class SignInViewModel @ViewModelInject constructor(
throw ex throw ex
} }
try { try {
authorizationService.performTokenRequest(request, clientAuthentication)?.let { authorizationServiceProvider
authStateManager.updateAfterTokenResponse(it, null) .google
if (authStateManager.current.isAuthorized) { .performTokenRequest(request, clientAuthentication)?.let {
Timber.d("Authorization successful") authStateManager.updateAfterTokenResponse(it, null)
} if (authStateManager.current.isAuthorized) {
} Timber.d("Authorization successful")
}
}
} catch (e: AuthorizationException) { } catch (e: AuthorizationException) {
authStateManager.updateAfterTokenResponse(null, e) authStateManager.updateAfterTokenResponse(null, e)
} }

@ -12,7 +12,7 @@ import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.internal.tls.OkHostnameVerifier import okhttp3.internal.tls.OkHostnameVerifier
import org.tasks.DebugNetworkInterceptor import org.tasks.DebugNetworkInterceptor
import org.tasks.auth.AuthorizationService import org.tasks.auth.AuthorizationServiceProvider
import org.tasks.billing.Inventory import org.tasks.billing.Inventory
import org.tasks.data.CaldavAccount import org.tasks.data.CaldavAccount
import org.tasks.preferences.Preferences import org.tasks.preferences.Preferences
@ -27,7 +27,7 @@ class CaldavClientProvider @Inject constructor(
private val preferences: Preferences, private val preferences: Preferences,
private val interceptor: DebugNetworkInterceptor, private val interceptor: DebugNetworkInterceptor,
private val inventory: Inventory, private val inventory: Inventory,
private val authorizationService: AuthorizationService private val authorizationServiceProvider: AuthorizationServiceProvider
) { ) {
suspend fun forUrl( suspend fun forUrl(
url: String?, url: String?,
@ -66,9 +66,11 @@ class CaldavClientProvider @Inject constructor(
token: String? = null token: String? = null
): Interceptor? { ): Interceptor? {
return when { return when {
account?.isTasksOrg == true -> authorizationService.getFreshToken()?.let { account?.isTasksOrg == true ->
TokenInterceptor(it, inventory) authorizationServiceProvider
} .google
.getFreshToken()
?.let { TokenInterceptor(it, inventory) }
username?.isNotBlank() == true && password?.isNotBlank() == true -> username?.isNotBlank() == true && password?.isNotBlank() == true ->
BasicDigestAuthHandler(null, username, password) BasicDigestAuthHandler(null, username, password)
token?.isNotBlank() == true -> token?.isNotBlank() == true ->
@ -106,6 +108,6 @@ class CaldavClientProvider @Inject constructor(
} }
fun dispose() { fun dispose() {
authorizationService.dispose() authorizationServiceProvider.dispose()
} }
} }
Loading…
Cancel
Save