📜 ⬆️ ⬇️

Account Manager: accounts, tokens and all-all-all. Yandex lecture

Android provides a powerful account management system. Having an Account Manager has helped Yandex for a long time - over the years of developing applications and services, we have gained a lot of experience related to Android authorization mechanisms. Learn about this experience from a lecture by developer Kirill Borisov. At the same time, you will understand how these systems will be useful to your application and how to avoid the pitfalls when interacting with them.


- I want to tell about one small Android subsystem. She rarely comes across her, very few have heard of her, but she can be useful to a much larger number of people. This Account Manager is a scary thing that manages accounts, tokens and everything connected with it.

Consider what an Android account is in theory, spherical in a vacuum. Then look at the Account Manager as such, at the service itself. And let's see what a thorny path Yandex went through in taming this beast.
')
Imagine: you are an ordinary developer, you have a small application. For more understanding, this is just a game where you have to line up three things in a row and everything will be fine.

And now let's make it so that the results of how many particles I put next, get into the Internet. To do this, you need some kind of cloud backend, where we will go and post the results.

We are connected with backend, all is well.

At some point, we understand that a backend that does not perform any user authentication is not the most useful thing.

Well, we add OAuth authentication to the application. Everything is good, but now it is necessary to store somewhere all these logins, user passwords, tokens associated with them. Therefore, in our application roll database with accounts. And an unexpectedly simple idea to brag to your friends is overgrown with a bunch of details.

What are the disadvantages of this approach? First, your accounts, all authorizations, the tokens associated with them, are stored in the application itself. Therefore, when the user no longer has enough space for the next photo of the next cat, he will simply open the list of applications, click “clear”, and suddenly all your achievements and logins will be lost. Sadness

Secondly, it is necessary to fully control this process. Know where tokens are, how to get them, how to handle them, where to throw requests to OAuth. And imagine that you have more than one application that uses the same backend. Each application will have to duplicate this logic, and so on.

And the least of your problems - you will have to log in and login through the application itself. Imagine that you have many applications, not like Yandex, but at least five. The user suddenly wanted to give the phone to his wife, he logged out in one application, in the second, third, fourth ... Inconvenient.

How to improve it? You can use the accounts feature.

All of you somehow met accounts. This is an ordinary nondescript item in the settings menu, you will see strange names there - Google, Yandex, add an account. The list may vary from phone to phone.

This is a group of system accounts that are used by various applications to store login data centrally: who went where, what credentials are associated with it, etc.

Why do you need it? The most important advantage is that the storage of credentials occurs outside the application. Now the user can delete the application, clear it, but if he logged in once, the next time you will know about it. This allows you to greatly reduce the load on your backend, which does not have to constantly handle “log in”, “log out” and so on, and also not force the user to log into the application time after time.

Secondly, you can abstract the authorization logic from your application, and having logged in once in one application, you can make so that in all applications connected with it, this authentication information is available.

It also becomes possible to manage accounts centrally. If you want to log in VasyaPupkin1, you can just go to the settings, accounts, click delete - everything, as if you were not on the phone.

The most delicious option is to use the Sync Adapter. This is the thing for which many generally bind to the Account Manager.

This piece allows you to create some code that will be launched by Android periodically, upon request, to change data in the content provider, and will allow you to update the data in the background, without starting the application itself.

Since some authentication may be needed, the accounts in the system also need this Sync Adapter Framework, so they are almost tightly connected in Android. You can not do such a thing to update the data in the background, if you do not add the system of accounts, and without an Account Manager it will not work.

Account Manager is an ordinary system service. A sort of abstract layer between your business logic and the logic of authorization associated with the backend.

Concurrently, he is the custodian of the system database of accounts, the very centralized pit where the logins and passwords of your applications fall.

If we return to the previously discussed scheme, that there is a backend, OAuth, application, and so on, then with the addition of the Account Manager, it will look like this.

Here, all our friends are also clouds, there is an application, but a proxy layer, Account Manager, has been added to our data picture. When an application wants to log in somewhere, on its backend, it does not go directly to the cloud authentication system, does not access any OAuth, it goes to the Account Manager service system and asks: login me, please, I need a token to request throw.

Account Manager already, hiding under the hood all the logic of authorization, allows the application not to think about what is happening there. He asked for a token - the token returned. Or did not return, which also happens.

If we look at the process closer, it looks like this. For brevity, the Account Manager layer itself is not shown here, because it is an interlayer between your application and the authenticator.

There is a certain getOauthToken, a system call to which we transfer the system account, it goes to the Account Manager, to the authenticator, and he already redirects him to the desired OAuth, requests the issuance of a token, receives it and sends it to the application.

The application in turn attaches it to the API request, throws it to the backend, the backend goes back to OAuth, checks the token and returns the response from the API.

The process is not much different from the standard OAuth authorization, but now your application does not need to think about it, and most importantly - do not interfere with the business logic.

What happens if we have more than one application? I already mentioned that with a single Account Manager, you can make authentication logic between multiple applications. Everything is quite simple, if there is Yandex.Mail, Yandex.Music, then they will most likely go to one backend if they have the same type of accounts, and they can simply use the services of the Account Manager, which will transfer their request to a single code authenticator. And the fact that he will transfer this token, he will save in the database of accounts.

By what principle does Account Manager understand that this application can be given access to this type of accounts with its token, but this is not possible? Everything is trite and simple: the same signature. Accounts and a group of accounts are divided between applications, if they have the same signature. If an abstract Facebook comes, he will not be able to ask for the data of Yandex accounts, simply because Android will say a security exception, sorry, your signature does not match.

If you go deeper, this is due to the implementation of the access control model in Android. Each application in terms of Linux, on the basis of which Android is built, is like a separate user. They have a separate UID number, each application has its own daddy of owners who have this same UID. The same thing happens with accounts. Each type of account corresponds to a certain UID. The application that manages these accounts, which include the authenticator, must match the signature with their clients. If our authenticator would have a non-Yandex signature, then Yandex.Mail and Yandex.Music would not be able to access the account, even if they knew what they were called, knew their passwords, etc.

Speaking of Facebook, what happens if there is another group of accounts in the system?

Nothing interesting, just add another application, another group of accounts to the system list, and a Facebook icon will appear next to the Yandex icon. They will have their own accounts, the division between which is provided by the Account Manager, Yandex does not see Facebook and cannot use its accounts, Facebook cannot use Yandex accounts. It's simple.

It is worth mentioning here how security it is. I used to store it next to my application, I knew that it was mine, nobody touched it, but now it is stored somewhere there.

In fact, these accounts are stored in the system database, access to which is only available for Android system services. The only normal way to get data from there, not being Android or the application that is responsible for them, is to get root on the phone. But if you have root on the phone, then you can do little to prevent it. You can pick up accounts, sniff traffic, and so on. We’ll assume that as long as you don’t break into someone else’s phone using root, accounts are quite secure, this is a sufficient guarantee in most cases.

Authenticator - this compound word flashes quite often. What is it like?

This is a banal class that extenndit is a banal abstract interface from Android itself, AbstractAccountAuthenticator. This is not a complete example of this class, since it is just a proxy that passes the request coming from the system Account Manager into its glue code.

How is he announced? The authenticator is part of some Android application, not being part of the system. If any type of accounts appear on your device, it means that it will be associated with an application. You can’t just create Yandex accounts on a phone where there are no Yandex applications. In the Yandex application, at least in one, this authenticator must be located, who will say to the system that hey, I am responsible for these types of accounts, please consider me the main one here.

How does he say that?

We have such XML-code, which is described in the application manifest, which exports the authenticator, and in fact, here is the minimum necessary amount of information. Some ID of your account type, which may or may not coincide with your application ID. You specify how to show your account, for example, Yandex, Facebook. Also you show two icons, big and small. Everything. When the system notices this in the manifest of your application, you can be responsible for a certain type of accounts.

And how to use it in your application? When your application throws a request to the Account Manager, the Account Manager goes to your authenticator, which is a banal service in your application.

Like all the binded services, you simply return an IBinder object that implements the interface, and work continues.

It is all very easy to contact. In your interface, you write meta-data, which indicates that you have a certain authenticator.xml, and the system begins to answer for this type of accounts, and tell your application, your authenticator, that a request has arrived, give me a token, add an account, and t dd

Let's look at an interesting situation. Imagine you have a service, an authenticator, it is built into your application. And then suddenly a second application appears on your system that implements the same type of accounts, there is the same authenticator. For example, you do not know in what order your user will put your application. If you knew that your user always puts one application before another, you could implement this code in the first application, and in the second call it. But life is more cruel, the user can put Yandex.Map first, then Yandex.Music, or vice versa, or forget about them and put Navigator in general. The phone must have at least one application that implements the authenticator. And there are two of them.

No problem with that. The system will take one of them, usually belonging to the application that appeared earlier, and will communicate with it. The remaining services will spin in the background, the system will ignore them. If the application containing Authenticator1 is deleted, the system will simply switch to the second transparently. And from the point of view of the application, nothing has changed, just asked the token, and who issued it, from which application, it should not be disturbed.

This imposes the requirement that the code that is implemented by this identifier, if possible, provide the same interface, contain the same logic between different applications.

It would seem, where does Yandex?

The need for our users to be in any Yandex application in their account, logged in to Music, then put another 20, and force them to log in each of them individually cruelly and inhumanly. That is why in the depths of our company a library was born long ago with the inspirational name Account Manager.

This will bring us further a lot of pain. It’s hard to explain how your Account Manager library interacts with the Account Manager service.

It is a single solution for working with Yandex accounts. If a Yandex application wants to work with these accounts — and it may not want it, we don’t mind, it’s his right — then it must integrate this library into itself so that there’s no difference between all applications about how to log in to the system, how to handle accounts. This is a very important requirement when your zoo application is developed by a bunch of different people.

It is used in almost all Yandex applications, both on Android and iOS. It tries to work well in quite difficult conditions.

Our first approach contained as many as 4 versions and 83 subminor versions, it implemented a master-client approach.

In conditions of limited memory, processor time, etc., we decided to make sure that we have exactly one working service for accounts, and in other applications in the system, the authenticator’s service will be like that, but will be muted. The system is quite uninteresting all that. She sees that there is one service working, she is knocking on him, everything is fine.

As if everything is great, but what happens if this application is removed?

Nothing good.

Further between all applications of Yandex on your phone there are choices of the master. Each application receives a list of all other applications on the phone, begins to search through it in search of an application with the highest version, and in the case of several such, with the earliest installation date. If it is equal to itself, then this application considers that it is a master, it includes a service. When it does it, the system sees that a new service has appeared, immediately picks it up. All is well.

What we did not take into account when entering this cruel world? On fairly slow phones or on fast phones with a huge number of Yandex applications or applications, in principle, the system may not have time to notice that a new authenticator has appeared, there are some choices going on ... The system then replenishes with question marks, shrugs and deletes all Yandex accounts. This situation happened often, and something had to be done about it.

We came up with such a cool thing. A content provider has been added to each authenticator, and a base under it. What was going on? When the application was a master, when it received information, usually through the system brodcast, that the list of accounts has changed, it went to this master and took away a copy of its account database. As a local small backup. And this gave the name of the “master-client” scheme, in fact it is the master-client replication.

What happens in a situation when such a question mark appears? The account manager sooner or later notices that someone who is responsible for Yandex accounts has reappeared in the system, is already empty in the system database. It goes to this application, and it pretends that this is the way it should, everything is great, it just takes accounts now not from the system database, but from the local small backup. From the user's point of view, nothing happened, here is a list of accounts.

In fact, the list of accounts between several applications sometimes went away. It happened that one list in Yandex.Music, another in Maps, another in Yandex there appeared some accounts that you forgot about a long time ago, but they were stored somewhere in the backup. It was unpleasant and uncomfortable.

The scheme, when one application stopped, and the other worked offline, we were greatly disturbed. It was especially fun when this situation happened.

When I tried to download the backup from the master application to the client application, this did not work. For example, the content provider was denied access to another content provider.

In what situations could this happen?

We were very surprised to learn that our good Chinese brothers in their firmware for the sake of common humanity realized energy conservation. Good firmware saw that one application was trying to go to another application and said: “You will awaken him! Make you have a battery! So it is impossible! ”And quietly dropping a request for data, the content simply did not reach.

Nowhere has this been written and documented. The only thing that made us suspicious and made us admit the problem was when we saw a debug message in the log by chance that such an intent would be dropped due to the rules of the internal firewall.

Also, these wonderful people happened to block our requests to the network for the Yandex backend for authentication, etc.

Unfortunately, nothing was done with this. , , . .

.

, . . .

— . , - . .

5.0 , , , — , , , , , , , .

? , . Account Manager, , n , , , . , . , , , Account Manager , Account Manager' — .

Content Provider . , . , . . , , .

, . , — . . , , Android 7.0 .

Google? Android 7.0 Android , , , , , .

. , . Android, , , . , - , , . , , , , , . . . Android 7.0 .

, . , , .

, , , , , .

- , , Android , . , . , , .

, . — .

, , , , , , Account Manager .

? , force stop. , , Xiaomi Meizu. , , , .

. , . , - , , , .

, — . What for? , , , .

, — . . . , . , , , . .

, SyncAdapter. , Android — , SyncAdapter, . , , . , . , .

, — , . , .

, , , , — , . , , , . , .

. - , Account Manager . - — , -, — , . . , , . .

. . , , , Android .

Source: https://habr.com/ru/post/347152/


All Articles