Skip to content

Commit 0d121e8

Browse files
authored
Fix workaccount setup (#3350)
* workaccount: Eliminate call to `AccountManager.addAccount` Intune now sets a policy such that users are not allowed to create work profiles anymore. This is good in principle because users are never supposed to do this manually (and are, in fact, incapable of doing so). Our code is also affected because `WorkAccountService` triggered sign-in flow in `WorkAccountAuthenticator` through `AccountManager.addAccount`, which is the action prohibited by the policy. We can still (and need to) call `AccountManager.addAccountExplicitly` to register the account with the system. * workaccount: fix sign in like 3a68bc3 i.e. same fix as #3257 * workaccount: cleanup
1 parent d9ea99d commit 0d121e8

2 files changed

Lines changed: 57 additions & 99 deletions

File tree

play-services-auth-workaccount/core/src/main/kotlin/com/google/android/gms/auth/account/authenticator/WorkAccountAuthenticator.kt

Lines changed: 53 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -38,74 +38,52 @@ class WorkAccountAuthenticator(val context: Context) : AbstractAccountAuthentica
3838
authTokenType: String?,
3939
requiredFeatures: Array<out String>?,
4040
options: Bundle
41-
): Bundle? {
42-
43-
if (!WorkProfileSettings(context).allowCreateWorkAccount) {
44-
return Bundle().apply {
45-
putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)
46-
putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.auth_work_authenticator_disabled_error)
47-
)
48-
}
49-
} else if (
50-
!options.containsKey(KEY_ACCOUNT_CREATION_TOKEN)
51-
|| options.getString(KEY_ACCOUNT_CREATION_TOKEN) == null
52-
|| options.getInt(AccountManager.KEY_CALLER_UID) != android.os.Process.myUid()) {
53-
Log.e(TAG,
54-
"refusing to add account without creation token or from external app: " +
55-
"could have been manually initiated by user (not supported) " +
56-
"or by unauthorized app (not allowed)"
41+
): Bundle {
42+
/* Calls to this method are always initiated by other applications or by the user.
43+
* We refuse, because `accountCreationToken` is needed, and because only profile owner is
44+
* supposed to provision this account. Profile owner will use `WorkAccountAuthenticator`
45+
* instead, which calls the code in `addAccountInternal` directly.
46+
*
47+
* Also note: adding account with `AccountManager.addAccount` can be forbidden by device
48+
* policy.
49+
*/
50+
return Bundle().apply {
51+
putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)
52+
putString(
53+
AccountManager.KEY_ERROR_MESSAGE,
54+
context.getString(R.string.auth_work_authenticator_add_manual_error)
5755
)
58-
59-
// TODO: The error message is not automatically displayed by the settings app as of now.
60-
// We can consider showing the error message through a popup instead.
61-
62-
return Bundle().apply {
63-
putInt(AccountManager.KEY_ERROR_CODE, AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION)
64-
putString(AccountManager.KEY_ERROR_MESSAGE, context.getString(R.string.auth_work_authenticator_add_manual_error)
65-
)
66-
}
6756
}
57+
}
6858

69-
val oauthToken: String = options.getString(KEY_ACCOUNT_CREATION_TOKEN)!!
59+
/**
60+
* @return `null` if account creation fails, the newly created account otherwise
61+
*/
62+
fun addAccountInternal(
63+
accountCreationToken: String
64+
): Account? {
7065

71-
try {
72-
tryAddAccount(oauthToken, response)
73-
} catch (exception: Exception) {
74-
response.onResult(Bundle().apply {
75-
putInt(
76-
AccountManager.KEY_ERROR_CODE,
77-
AccountManager.ERROR_CODE_NETWORK_ERROR
78-
)
79-
putString(AccountManager.KEY_ERROR_MESSAGE, exception.message)
80-
})
66+
if (!WorkProfileSettings(context).allowCreateWorkAccount) {
67+
// TODO: communicate error to user (use `R.string.auth_work_authenticator_disabled_error`)
68+
Log.w(TAG, "creating a work account is disabled in microG settings")
69+
return null
8170
}
8271

83-
/* Note: as is not documented, `null` must only be returned after `response.onResult` was
84-
* already called, hence forcing the requests to be synchronous. They are still async to
85-
* the caller's main thread because AccountManager forces potentially blocking operations,
86-
* like waiting for a response upon `addAccount`, not to be on the main thread.
87-
*/
88-
return null
89-
}
90-
91-
@Throws(Exception::class)
92-
private fun tryAddAccount(
93-
oauthToken: String,
94-
response: AccountAuthenticatorResponse
95-
) {
96-
val authResponse = AuthRequest().fromContext(context)
97-
.appIsGms()
98-
.callerIsGms()
99-
.service("ac2dm")
100-
.token(oauthToken).isAccessToken()
101-
.addAccount()
102-
.getAccountId()
103-
.droidguardResults(null)
104-
.response
105-
106-
val accountManager = AccountManager.get(context)
107-
if (accountManager.addAccountExplicitly(
108-
Account(authResponse.email, AuthConstants.WORK_ACCOUNT_TYPE),
72+
return try {
73+
val authResponse = AuthRequest().fromContext(context)
74+
.appIsGms()
75+
.callerIsGms()
76+
.service("ac2dm")
77+
.token(accountCreationToken).isAccessToken()
78+
.addAccount()
79+
.getAccountId()
80+
.droidguardResults("null") // TODO
81+
.response
82+
83+
val accountManager = AccountManager.get(context)
84+
val account = Account(authResponse.email, AuthConstants.WORK_ACCOUNT_TYPE)
85+
val accountAdded = accountManager.addAccountExplicitly(
86+
account,
10987
authResponse.token, Bundle().apply {
11088
// Work accounts have no SID / LSID ("BAD_COOKIE") and no first/last name.
11189
if (authResponse.accountId.isNotBlank()) {
@@ -119,20 +97,21 @@ class WorkAccountAuthenticator(val context: Context) : AbstractAccountAuthentica
11997
"unexpected 'services' value ${authResponse.services} (usually 'android')"
12098
)
12199
}
122-
}
123-
)
124-
) {
100+
})
125101

126-
// Notify vending package
127-
context.sendBroadcast(
128-
Intent(WORK_ACCOUNT_CHANGED_BOARDCAST).setPackage("com.android.vending")
129-
)
102+
if (accountAdded) {
130103

131-
// Report successful creation to caller
132-
response.onResult(Bundle().apply {
133-
putString(AccountManager.KEY_ACCOUNT_NAME, authResponse.email)
134-
putString(AccountManager.KEY_ACCOUNT_TYPE, AuthConstants.WORK_ACCOUNT_TYPE)
135-
})
104+
// Notify vending package
105+
context.sendBroadcast(
106+
Intent(WORK_ACCOUNT_CHANGED_BOARDCAST).setPackage("com.android.vending")
107+
)
108+
109+
// Report successful creation to caller
110+
account
111+
} else null
112+
} catch (exception: Exception) {
113+
Log.w(TAG, "Failed to add work account.", exception)
114+
null
136115
}
137116
}
138117

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

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

237-
const val KEY_ACCOUNT_CREATION_TOKEN = "creationToken"
238216
private const val KEY_GOOGLE_USER_ID = AuthConstants.GOOGLE_USER_ID
239217
}
240218
}

play-services-auth-workaccount/core/src/main/kotlin/org/microg/gms/auth/workaccount/WorkAccountService.kt

Lines changed: 4 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -13,12 +13,11 @@ import android.content.Context
1313
import android.content.Intent
1414
import android.content.pm.PackageManager
1515
import android.os.Build.VERSION.SDK_INT
16-
import android.os.Bundle
1716
import android.os.Parcel
1817
import android.util.Log
1918
import com.google.android.gms.auth.account.IWorkAccountCallback
2019
import com.google.android.gms.auth.account.IWorkAccountService
21-
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator.Companion.KEY_ACCOUNT_CREATION_TOKEN
20+
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator
2221
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticator.Companion.WORK_ACCOUNT_CHANGED_BOARDCAST
2322
import com.google.android.gms.auth.account.authenticator.WorkAccountAuthenticatorService
2423
import com.google.android.gms.common.Feature
@@ -27,7 +26,6 @@ import com.google.android.gms.common.internal.ConnectionInfo
2726
import com.google.android.gms.common.internal.GetServiceRequest
2827
import com.google.android.gms.common.internal.IGmsCallbacks
2928
import org.microg.gms.BaseService
30-
import org.microg.gms.auth.AuthConstants
3129
import org.microg.gms.common.GmsService
3230
import org.microg.gms.common.PackageUtils
3331

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

9896
override fun addWorkAccount(
9997
callback: IWorkAccountCallback?,
100-
token: String?
98+
token: String
10199
) {
102100
Log.d(TAG, "addWorkAccount with token $token")
103-
val future = accountManager.addAccount(
104-
AuthConstants.WORK_ACCOUNT_TYPE,
105-
null,
106-
null,
107-
Bundle().apply { putString(KEY_ACCOUNT_CREATION_TOKEN, token) },
108-
null,
109-
null,
110-
null
111-
)
112101
Thread {
113-
try {
114-
future.result.let { result ->
115-
callback?.onAccountAdded(
116-
Account(
117-
result.getString(AccountManager.KEY_ACCOUNT_NAME)!!,
118-
result.getString(AccountManager.KEY_ACCOUNT_TYPE)!!
119-
)
120-
)
121-
}
122-
} catch (e: Exception) {
123-
Log.e(TAG, "could not add work account with error message: ${e.message}")
102+
WorkAccountAuthenticator(context).addAccountInternal(token)?.let {
103+
callback?.onAccountAdded(it)
124104
}
125105
}.start()
126106
}

0 commit comments

Comments
 (0)