Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -38,74 +38,52 @@ class WorkAccountAuthenticator(val context: Context) : AbstractAccountAuthentica
authTokenType: String?,
requiredFeatures: Array<out String>?,
options: Bundle
): Bundle? {

if (!WorkProfileSettings(context).allowCreateWorkAccount) {
return Bundle().apply {
putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)
putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.auth_work_authenticator_disabled_error)
)
}
} else if (
!options.containsKey(KEY_ACCOUNT_CREATION_TOKEN)
|| options.getString(KEY_ACCOUNT_CREATION_TOKEN) == null
|| options.getInt(AccountManager.KEY_CALLER_UID) != android.os.Process.myUid()) {
Log.e(TAG,
"refusing to add account without creation token or from external app: " +
"could have been manually initiated by user (not supported) " +
"or by unauthorized app (not allowed)"
): Bundle {
/* Calls to this method are always initiated by other applications or by the user.
* We refuse, because `accountCreationToken` is needed, and because only profile owner is
* supposed to provision this account. Profile owner will use `WorkAccountAuthenticator`
* instead, which calls the code in `addAccountInternal` directly.
*
* Also note: adding account with `AccountManager.addAccount` can be forbidden by device
* policy.
*/
return Bundle().apply {
putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)
putString(
AccountManager.KEY_ERROR_MESSAGE,
context.getString(R.string.auth_work_authenticator_add_manual_error)
)

// TODO: The error message is not automatically displayed by the settings app as of now.
// We can consider showing the error message through a popup instead.

return Bundle().apply {
putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)
putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.auth_work_authenticator_add_manual_error)
)
}
}
}

val oauthToken: String = options.getString(KEY_ACCOUNT_CREATION_TOKEN)!!
/**
* @return `null` if account creation fails, the newly created account otherwise
*/
fun addAccountInternal(
accountCreationToken: String
): Account? {

try {
tryAddAccount(oauthToken, response)
} catch (exception: Exception) {
response.onResult(Bundle().apply {
putInt(
AccountManager.KEY_ERROR_CODE,
AccountManager.ERROR_CODE_NETWORK_ERROR
)
putString(AccountManager.KEY_ERROR_MESSAGE, exception.message)
})
if (!WorkProfileSettings(context).allowCreateWorkAccount) {
// TODO: communicate error to user (use `R.string.auth_work_authenticator_disabled_error`)
Log.w(TAG, "creating a work account is disabled in microG settings")
return null
}

/* Note: as is not documented, `null` must only be returned after `response.onResult` was
* already called, hence forcing the requests to be synchronous. They are still async to
* the caller's main thread because AccountManager forces potentially blocking operations,
* like waiting for a response upon `addAccount`, not to be on the main thread.
*/
return null
}

@Throws(Exception::class)
private fun tryAddAccount(
oauthToken: String,
response: AccountAuthenticatorResponse
) {
val authResponse = AuthRequest().fromContext(context)
.appIsGms()
.callerIsGms()
.service("ac2dm")
.token(oauthToken).isAccessToken()
.addAccount()
.getAccountId()
.droidguardResults(null)
.response

val accountManager = AccountManager.get(context)
if (accountManager.addAccountExplicitly(
Account(authResponse.email, AuthConstants.WORK_ACCOUNT_TYPE),
return try {
val authResponse = AuthRequest().fromContext(context)
.appIsGms()
.callerIsGms()
.service("ac2dm")
.token(accountCreationToken).isAccessToken()
.addAccount()
.getAccountId()
.droidguardResults("null") // TODO
.response

val accountManager = AccountManager.get(context)
val account = Account(authResponse.email, AuthConstants.WORK_ACCOUNT_TYPE)
val accountAdded = accountManager.addAccountExplicitly(
account,
authResponse.token, Bundle().apply {
// Work accounts have no SID / LSID ("BAD_COOKIE") and no first/last name.
if (authResponse.accountId.isNotBlank()) {
Expand All @@ -119,20 +97,21 @@ class WorkAccountAuthenticator(val context: Context) : AbstractAccountAuthentica
"unexpected 'services' value ${authResponse.services} (usually 'android')"
)
}
}
)
) {
})

// Notify vending package
context.sendBroadcast(
Intent(WORK_ACCOUNT_CHANGED_BOARDCAST).setPackage("com.android.vending")
)
if (accountAdded) {

// Report successful creation to caller
response.onResult(Bundle().apply {
putString(AccountManager.KEY_ACCOUNT_NAME, authResponse.email)
putString(AccountManager.KEY_ACCOUNT_TYPE, AuthConstants.WORK_ACCOUNT_TYPE)
})
// Notify vending package
context.sendBroadcast(
Intent(WORK_ACCOUNT_CHANGED_BOARDCAST).setPackage("com.android.vending")
)

// Report successful creation to caller
account
} else null
} catch (exception: Exception) {
Log.w(TAG, "Failed to add work account.", exception)
null
}
}

Expand Down Expand Up @@ -234,7 +213,6 @@ class WorkAccountAuthenticator(val context: Context) : AbstractAccountAuthentica

const val WORK_ACCOUNT_CHANGED_BOARDCAST = "org.microg.vending.WORK_ACCOUNT_CHANGED"

const val KEY_ACCOUNT_CREATION_TOKEN = "creationToken"
private const val KEY_GOOGLE_USER_ID = AuthConstants.GOOGLE_USER_ID
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,11 @@ import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
import android.os.Parcel
import android.util.Log
import com.google.android.gms.auth.account.IWorkAccountCallback
import com.google.android.gms.auth.account.IWorkAccountService
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator.Companion.KEY_ACCOUNT_CREATION_TOKEN
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator.Companion.WORK_ACCOUNT_CHANGED_BOARDCAST
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticatorService
import com.google.android.gms.common.Feature
Expand All @@ -27,7 +26,6 @@ import com.google.android.gms.common.internal.ConnectionInfo
import com.google.android.gms.common.internal.GetServiceRequest
import com.google.android.gms.common.internal.IGmsCallbacks
import org.microg.gms.BaseService
import org.microg.gms.auth.AuthConstants
import org.microg.gms.common.GmsService
import org.microg.gms.common.PackageUtils

Expand Down Expand Up @@ -97,30 +95,12 @@ class WorkAccountServiceImpl(val context: Context) : IWorkAccountService.Stub()

override fun addWorkAccount(
callback: IWorkAccountCallback?,
token: String?
token: String
) {
Log.d(TAG, "addWorkAccount with token $token")
val future = accountManager.addAccount(
AuthConstants.WORK_ACCOUNT_TYPE,
null,
null,
Bundle().apply { putString(KEY_ACCOUNT_CREATION_TOKEN, token) },
null,
null,
null
)
Thread {
try {
future.result.let { result ->
callback?.onAccountAdded(
Account(
result.getString(AccountManager.KEY_ACCOUNT_NAME)!!,
result.getString(AccountManager.KEY_ACCOUNT_TYPE)!!
)
)
}
} catch (e: Exception) {
Log.e(TAG, "could not add work account with error message: ${e.message}")
WorkAccountAuthenticator(context).addAccountInternal(token)?.let {
callback?.onAccountAdded(it)
}
}.start()
}
Expand Down